Skip to content

Commit

Permalink
Introduce new models TransformationMapping and TransformationMappingItem
Browse files Browse the repository at this point in the history
Create a complete mapping through a virtual column.
  • Loading branch information
bzwei committed Feb 6, 2018
1 parent a07ec73 commit 253410d
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 0 deletions.
67 changes: 67 additions & 0 deletions app/models/transformation_mapping.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
class TransformationMapping < ApplicationRecord
has_many :transformation_mapping_items, :dependent => :destroy

validates :name, :presence => true, :uniqueness => true

virtual_column :mappings, :type => :string

# forward compatible: next release the table will be polymorphic
virtual_column :type, :type => :string

def self.inheritance_column
"none"
end

def type
"MigrationInfrastructureMapping"
end

def type=(type)
end

# Assumption: source and destination types are the same. Works for infrastructure mapping
# group mapping items first by destination_type, then by destination_id
# simplify records with IDs.
# Sample result (Hash)
#
# EmsCluster:
# - destination: "2":
# sources: ["100", "200"]
# - destination: "3"
# sources: ["301", "302"]
# Network:
# - destination: "2"
# sources: ["202", "204"]
# Storage:
# - destination: "4"
# sources: ["33", "32"]
def mappings
dst_type_groups = transformation_mapping_items.group_by(&:destination_type)
dst_type_groups.each_with_object({}) do |(dst_type, items), results|
dst_groups = items.group_by { |item| item.destination_id.to_s }
results[dst_type] = dst_groups.each_with_object([]) do |(dst_id, item_array), dst_id_groups|
dst_id_groups << {"destination" => dst_id, "sources" => item_array.collect { |item| item.source_id.to_s }}
end
end
end

def mappings=(options)
options.each do |dst_type, item_map_array|
item_map_array.each do |item_map|
destination_id = item_map['destination']
item_map['sources'].each do |source_id|
transformation_mapping_items << TransformationMappingItem.new(
:source_id => source_id,
:source_type => dst_type,
:destination_id => destination_id,
:destination_type => dst_type.camelize
)
end
end
end
end

def map(source)
transformation_mapping_items.find_by(:source => source).try(:destination)
end
end
7 changes: 7 additions & 0 deletions app/models/transformation_mapping_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class TransformationMappingItem < ApplicationRecord
belongs_to :transformation_mapping
belongs_to :source, :polymorphic => true
belongs_to :destination, :polymorphic => true

validates :source_id, :uniqueness => {:scope => [:transformation_mapping_id, :source_type]}
end
5 changes: 5 additions & 0 deletions spec/factories/transformation_mapping.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FactoryGirl.define do
factory :transformation_mapping do
sequence(:name) { |n| "Transformation Mapping #{seq_padded_for_sorting(n)}" }
end
end
3 changes: 3 additions & 0 deletions spec/factories/transformation_mapping_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FactoryGirl.define do
factory :transformation_mapping_item
end
43 changes: 43 additions & 0 deletions spec/models/transformation_mapping_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
describe TransformationMapping do
let(:src1) { Array.new(4) { FactoryGirl.create(:ems_cluster) } }
let(:dst1) { Array.new(2) { FactoryGirl.create(:ems_cluster) } }
let(:src2) { Array.new(2) { FactoryGirl.create(:network) } }
let(:dst2) { Array.new(2) { FactoryGirl.create(:network) } }
let(:mappings) do
{
"EmsCluster" => [
{ "sources" => [src1[0].id.to_s, src1[1].id.to_s], "destination" => dst1[0].id.to_s },
{ "sources" => [src1[2].id.to_s, src1[3].id.to_s], "destination" => dst1[1].id.to_s }
],
"Network" => [
{ "sources" => [src2[0].id.to_s], "destination" => dst2[0].id.to_s },
{ "sources" => [src2[1].id.to_s], "destination" => dst2[1].id.to_s }
]
}
end

context "CRUD" do
it 'creates a complete mapping with item from a hash representation' do
tm = FactoryGirl.create(:transformation_mapping, :mappings => mappings)
expect(tm.map(src1[0])).to eq(dst1[0])
expect(tm.map(src1[1])).to eq(dst1[0])
expect(tm.map(src1[2])).to eq(dst1[1])
expect(tm.map(src1[3])).to eq(dst1[1])
expect(tm.map(src2[0])).to eq(dst2[0])
expect(tm.map(src2[1])).to eq(dst2[1])
end

it 'reads a complete mapping in a hash representation' do
tm = FactoryGirl.create(:transformation_mapping)
tm.transformation_mapping_items << TransformationMappingItem.new(:source => src1[0], :destination => dst1[0])
tm.transformation_mapping_items << TransformationMappingItem.new(:source => src1[1], :destination => dst1[0])
tm.transformation_mapping_items << TransformationMappingItem.new(:source => src1[2], :destination => dst1[1])
tm.transformation_mapping_items << TransformationMappingItem.new(:source => src1[3], :destination => dst1[1])
tm.transformation_mapping_items << TransformationMappingItem.new(:source => src2[0], :destination => dst2[0])
tm.transformation_mapping_items << TransformationMappingItem.new(:source => src2[1], :destination => dst2[1])
tm.save

expect(tm.mappings).to eq(mappings)
end
end
end

0 comments on commit 253410d

Please sign in to comment.