-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
set vm ancestry from relationship resource info
- Loading branch information
Showing
2 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
class AddAncestryToVm < ActiveRecord::Migration[5.2] | ||
class VmOrTemplate < ActiveRecord::Base | ||
self.inheritance_column = :_type_disabled | ||
self.table_name = 'vms' | ||
has_many :all_relationships, :class_name => "AddAncestryToVm::Relationship", :dependent => :destroy, :as => :resource | ||
end | ||
|
||
class Vm < VmOrTemplate | ||
end | ||
|
||
class Relationship < ActiveRecord::Base | ||
belongs_to :vm, :class_name => 'AddAncestryToVm::VmOrTemplate', :foreign_key => :vm_id | ||
end | ||
|
||
def up | ||
add_column :vms, :ancestry, :string | ||
add_index :vms, :ancestry | ||
|
||
say_with_time("set vm ancestry from existing genealogy relationship resource information") do | ||
connection.execute <<-SQL | ||
UPDATE vms | ||
SET ancestry = new_ancestry | ||
FROM ( | ||
SELECT ancestor_resources_for_vms.vm_id AS vm_id, | ||
ARRAY_TO_STRING(ARRAY_AGG(res_rels.resource_id)::VARCHAR[], '/') AS new_ancestry | ||
FROM ( | ||
SELECT vms.id AS vm_id, relationships.id AS rel_id | ||
FROM vms | ||
JOIN relationships a_rels ON a_rels.resource_id = vms.id | ||
AND a_rels.relationship = 'genealogy' | ||
AND a_rels.resource_type = 'VmOrTemplate' | ||
LEFT JOIN LATERAL UNNEST(STRING_TO_ARRAY(a_rels.ancestry, '/')::BIGINT[]) | ||
WITH ORDINALITY AS relationships(id, indx) ON TRUE | ||
ORDER BY vms.id, relationships.indx | ||
) AS ancestor_resources_for_vms | ||
JOIN relationships res_rels ON res_rels.id = ancestor_resources_for_vms.rel_id AND res_rels.relationship = 'genealogy' | ||
GROUP BY ancestor_resources_for_vms.vm_id | ||
) AS new_ancestors_for_vms | ||
WHERE new_ancestors_for_vms.vm_id = vms.id | ||
SQL | ||
end | ||
|
||
connection.execute <<-SQL | ||
DELETE FROM relationships | ||
WHERE relationship = 'genealogy' AND resource_type = 'VmOrTemplate' | ||
AND resource_id | ||
IN (SELECT vms.id FROM vms); | ||
SQL | ||
end | ||
|
||
def down | ||
say_with_time("create relationship records from vm ancestry") do | ||
vms_with_ancestry = Vm.select { |vm| vm.ancestry.present? } | ||
vms_with_ancestry.each do |vm| | ||
Relationship.create!(:relationship => 'genealogy', :resource_type => 'VmOrTemplate', :resource_id => vm.id, :ancestry => vm.ancestry) | ||
end | ||
|
||
remove_column :vms, :ancestry | ||
end | ||
end | ||
end |
138 changes: 138 additions & 0 deletions
138
spec/migrations/20200607025146_add_ancestry_to_vm_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
require_migration | ||
|
||
describe AddAncestryToVm do | ||
let(:rel_stub) { migration_stub(:Relationship) } | ||
let(:vm_stub) { migration_stub :VmOrTemplate } | ||
let(:vm) { vm_stub.create! } | ||
let(:vm2) { vm_stub.create! } | ||
let(:vm3) { vm_stub.create! } | ||
let(:vm4) { vm_stub.create! } | ||
let(:vm5) { vm_stub.create! } | ||
let(:vm6) { vm_stub.create! } | ||
let(:root) { vm_stub.create! } | ||
|
||
migration_context :up do | ||
context "single parent/child rel" do | ||
it 'updates ancestry' do | ||
parent_rel = rel_stub.create!(:relationship => 'genealogy', :ancestry => nil, :resource_type => 'VmOrTemplate', :resource_id => root.id) | ||
rel_stub.create!(:relationship => 'genealogy', :ancestry => parent_rel.id, :resource_type => 'VmOrTemplate', :resource_id => vm.id) | ||
|
||
migrate | ||
|
||
expect(vm.reload.ancestry).to eq(root.id.to_s) | ||
expect(root.reload.ancestry).to eq(nil) | ||
expect(AddAncestryToVm::Relationship.count).to eq(0) | ||
end | ||
end | ||
|
||
context "slightly more complicated tree" do | ||
it 'updates ancestry' do | ||
parent_rel = rel_stub.create!(:relationship => 'genealogy', :ancestry => nil, :resource_type => 'VmOrTemplate', :resource_id => root.id) | ||
child_rel = rel_stub.create!(:relationship => 'genealogy', :ancestry => parent_rel.id, :resource_type => 'VmOrTemplate', :resource_id => vm.id) | ||
rel_stub.create!(:relationship => 'genealogy', :ancestry => child_rel.id.to_s + '/' + parent_rel.id.to_s, :resource_type => 'VmOrTemplate', :resource_id => vm2.id) | ||
|
||
migrate | ||
|
||
expect(vm.reload.ancestry).to eq(root.id.to_s) | ||
expect(vm2.reload.ancestry).to eq("#{vm.id}/#{root.id}") | ||
expect(root.reload.ancestry).to eq(nil) | ||
expect(AddAncestryToVm::Relationship.count).to eq(0) | ||
end | ||
end | ||
|
||
context "complicated tree" do | ||
# a | ||
# b c | ||
# d g | ||
# e f | ||
it 'updates ancestry' do | ||
rel_a = rel_stub.create!(:relationship => 'genealogy', :ancestry => nil, :resource_type => 'VmOrTemplate', :resource_id => root.id) | ||
rel_c = rel_stub.create!(:relationship => 'genealogy', :ancestry => rel_a.id, :resource_type => 'VmOrTemplate', :resource_id => vm.id) | ||
rel_stub.create!(:relationship => 'genealogy', :ancestry => rel_c.id.to_s + '/' + rel_a.id.to_s, :resource_type => 'VmOrTemplate', :resource_id => vm2.id) | ||
rel_b = rel_stub.create!(:relationship => 'genealogy', :ancestry => rel_a.id.to_s, :resource_type => 'VmOrTemplate', :resource_id => vm3.id) | ||
rel_d = rel_stub.create!(:relationship => 'genealogy', :ancestry => rel_b.id.to_s + '/' + rel_a.id.to_s, :resource_type => 'VmOrTemplate', :resource_id => vm4.id) | ||
rel_stub.create!(:relationship => 'genealogy', :ancestry => rel_d.id.to_s + '/' + rel_b.id.to_s + '/' + rel_a.id.to_s, :resource_type => 'VmOrTemplate', :resource_id => vm5.id) | ||
rel_stub.create!(:relationship => 'genealogy', :ancestry => rel_d.id.to_s + '/' + rel_b.id.to_s + '/' + rel_a.id.to_s, :resource_type => 'VmOrTemplate', :resource_id => vm6.id) | ||
|
||
migrate | ||
|
||
expect(vm5.reload.ancestry).to eq("#{vm4.id}/#{vm3.id}/#{root.id}") | ||
expect(vm6.reload.ancestry).to eq("#{vm4.id}/#{vm3.id}/#{root.id}") | ||
expect(vm3.reload.ancestry).to eq(root.id.to_s) | ||
expect(vm.reload.ancestry).to eq(root.id.to_s) | ||
expect(vm2.reload.ancestry).to eq("#{vm.id}/#{root.id}") | ||
expect(root.reload.ancestry).to eq(nil) | ||
expect(AddAncestryToVm::Relationship.count).to eq(0) | ||
end | ||
end | ||
|
||
context "vm without rels" do | ||
it 'nil ancestry' do | ||
migrate | ||
|
||
expect(AddAncestryToVm::Vm.find(vm.id).ancestry).to eq(nil) | ||
end | ||
end | ||
|
||
context "with only ems_metadata relationship tree" do | ||
it 'sets nothing' do | ||
parent_rel = rel_stub.create!(:relationship => 'ems_metadata', :ancestry => nil, :resource_type => 'VmOrTemplate', :resource_id => root.id) | ||
rel_stub.create!(:relationship => 'ems_metadata', :ancestry => parent_rel.id, :resource_type => 'VmOrTemplate', :resource_id => vm.id) | ||
|
||
migrate | ||
|
||
expect(vm.reload.ancestry).to eq(nil) | ||
expect(root.reload.ancestry).to eq(nil) | ||
expect(AddAncestryToVm::Relationship.count).to eq(2) | ||
end | ||
end | ||
|
||
context "with both genealogy and ems_metadata rels" do | ||
it 'only sets ancestry from genealogy rels' do | ||
invalid_parent_rel = rel_stub.create!(:relationship => 'ems_metadata', :ancestry => nil, :resource_type => 'VmOrTemplate', :resource_id => root.id) | ||
rel_stub.create!(:relationship => 'ems_metadata', :ancestry => invalid_parent_rel.id, :resource_type => 'VmOrTemplate', :resource_id => vm.id) | ||
parent_rel = rel_stub.create!(:relationship => 'genealogy', :ancestry => nil, :resource_type => 'VmOrTemplate', :resource_id => root.id) | ||
rel_stub.create!(:relationship => 'genealogy', :ancestry => parent_rel.id, :resource_type => 'VmOrTemplate', :resource_id => vm.id) | ||
|
||
migrate | ||
|
||
expect(vm.reload.ancestry).to eq(root.id.to_s) | ||
expect(root.reload.ancestry).to eq(nil) | ||
expect(AddAncestryToVm::Relationship.count).to eq(2) | ||
end | ||
end | ||
end | ||
|
||
|
||
migration_context :down do | ||
context "multiple rels" do | ||
let(:vm) { vm_stub.create!(:ancestry => '6/5/4') } | ||
it 'creates rel and removes ancestry' do | ||
vm | ||
|
||
migrate | ||
|
||
rel = AddAncestryToVm::Relationship.first | ||
expect(rel.relationship).to eq('genealogy') | ||
expect(rel.ancestry).to eq('6/5/4') | ||
expect(rel.resource_type).to eq('VmOrTemplate') | ||
expect(rel.resource_id).to eq(vm.id) | ||
end | ||
end | ||
|
||
context "single rel" do | ||
let(:vm) { vm_stub.create!(:ancestry => '645') } | ||
it 'creates rel and removes ancestry' do | ||
vm | ||
|
||
migrate | ||
|
||
rel = AddAncestryToVm::Relationship.first | ||
expect(rel.relationship).to eq('genealogy') | ||
expect(rel.ancestry).to eq('645') | ||
expect(rel.resource_type).to eq('VmOrTemplate') | ||
expect(rel.resource_id).to eq(vm.id) | ||
end | ||
end | ||
end | ||
end |