Skip to content

Commit

Permalink
Migrate existing dialog field association data to use new relationship
Browse files Browse the repository at this point in the history
  • Loading branch information
d-m-u committed Oct 30, 2017
1 parent 3b374e6 commit a860e35
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
class MigrateDialogFieldAssociationsToUseNewRelationship < ActiveRecord::Migration[5.0]
class Dialog < ActiveRecord::Base
end

class DialogTab < ActiveRecord::Base
belongs_to :dialog, :class_name => "MigrateDialogFieldAssociationsToUseNewRelationship::Dialog"
end

class DialogGroup < ActiveRecord::Base
belongs_to :dialog_tab, :class_name => "MigrateDialogFieldAssociationsToUseNewRelationship::DialogTab"
end

class DialogField < ActiveRecord::Base
self.inheritance_column = :_type_disabled # disable STI
belongs_to :dialog_group, :class_name => "MigrateDialogFieldAssociationsToUseNewRelationship::DialogGroup"
end

class DialogFieldAssociation < ActiveRecord::Base
end

def up
say_with_time("Migrating existing dialog field associations to new relationship") do
dialog_with_fields.each do |_dialog, fields|
dialog_triggers = dialog_fields_with_trigger_auto_refresh(fields).sort_by! { |trigger| trigger[:position] }
dialog_responders = dialog_fields_with_auto_refresh(fields)
dialog_triggers.each_with_index do |trigger, index|
specific_responders = dialog_responders.select { |responder| responder_range(trigger, trigger[index + 1]).cover?(responder[:position]) }
set_associations(trigger, specific_responders)
end
end
end
end

def down
DialogFieldAssociation.delete_all
end

private

def absolute_position(dialog_fields)
dialog_fields.collect do |f|
field_position = f.position
dialog_group_position = f.dialog_group.position
dialog_tab_position = f.dialog_group.dialog_tab.position
index = field_position + dialog_group_position * 1000 + dialog_tab_position * 100_000
{:id => f.id, :position => index}
end
end

def dialog_fields_with_auto_refresh(dialog_fields)
absolute_position(dialog_fields.select(&:auto_refresh))
end

def dialog_fields_with_trigger_auto_refresh(dialog_fields)
absolute_position(dialog_fields.select(&:trigger_auto_refresh))
end

def responder_range(trigger_min, trigger_max)
min = trigger_min[:position] + 1
max = trigger_max.present? ? trigger_max[:position] - 1 : 100_000_000
(min..max)
end

def set_associations(trigger, specific_responders)
specific_responders.each { |responder| DialogFieldAssociation.create!(:trigger_id => trigger[:id], :respond_id => responder[:id]) }
end

def dialog_with_fields
DialogField
.where(:auto_refresh => true)
.or(DialogField.where(:trigger_auto_refresh => true))
.includes(:dialog_group => {:dialog_tab => :dialog})
.group_by { |f| f.dialog_group.try(:dialog_tab).try(:dialog) }
.except(nil)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
require_migration

describe MigrateDialogFieldAssociationsToUseNewRelationship do
let(:dialog_field_stub) { migration_stub(:DialogField) }
let(:dialog_group_stub) { migration_stub(:DialogGroup) }
let(:dialog_tab_stub) { migration_stub(:DialogTab) }
let(:dialog_stub) { migration_stub(:Dialog) }
let(:dialog_field_association_stub) { migration_stub(:DialogFieldAssociation) }
let(:dialog_group_id) { dialog_group_stub.first.id }
let(:dialog_tab_id) { dialog_tab_stub.first.id }
let(:dialog_id) { dialog_stub.first.id }

migration_context :up do
before do
dialog_stub.create!
dialog_tab_stub.create!(:dialog_id => dialog_id, :position => 4)
dialog_group_stub.create!(:dialog_tab_id => dialog_tab_id, :position => 7)
end

it "does not create a reference when trigger field is after responder field" do
dialog_field_stub.create!(:name => "dialog_field4", :auto_refresh => true, :position => 0, :dialog_group_id => dialog_group_id, :type => "DialogFieldTextbox")
dialog_field_stub.create!(:name => "dialog_field1", :trigger_auto_refresh => true, :position => 4, :dialog_group_id => dialog_group_id, :type => "DialogFieldDropdown")
expect(dialog_field_association_stub.count).to eq(0)

migrate

expect(dialog_field_association_stub.count).to eq(0)
end

it "does not create a circular reference" do
dialog_field_stub.create!(:name => "dialog_field4", :trigger_auto_refresh => true, :auto_refresh => true, :position => 0, :dialog_group_id => dialog_group_id, :type => "DialogFieldRadioButton")
dialog_field_stub.create!(:name => "dialog_field1", :auto_refresh => true, :trigger_auto_refresh => true, :position => 4, :dialog_group_id => dialog_group_id, :type => "DialogFieldTagControl")
expect(dialog_field_association_stub.count).to eq(0)

migrate

expect(dialog_field_association_stub.count).to eq(1)
expect(dialog_field_association_stub.first.trigger_id).to eq(dialog_field_stub.first.id)
expect(dialog_field_association_stub.first.respond_id).to eq(dialog_field_stub.second.id)
end

it "does create a reference when valid one is present" do
dialog_field_stub.create!(:name => "dialog_field4", :auto_refresh => true, :position => 2, :dialog_group_id => dialog_group_id)
dialog_field_stub.create!(:name => "dialog_field1", :trigger_auto_refresh => true, :position => 0, :dialog_group_id => dialog_group_id)
expect(dialog_field_association_stub.count).to eq(0)

migrate

expect(dialog_field_association_stub.count).to eq(1)
expect(dialog_field_association_stub.first.trigger_id).to eq(dialog_field_stub.second.id)
expect(dialog_field_association_stub.first.respond_id).to eq(dialog_field_stub.first.id)
end

it "does not create association when dialog tab is missing" do
dialog_tab_stub.delete_all
dialog_field_stub.create!(:name => "dialog_field4", :auto_refresh => true, :position => 2, :dialog_group_id => dialog_group_stub.first.id)
dialog_field_stub.create!(:name => "dialog_field1", :trigger_auto_refresh => true, :position => 0, :dialog_group_id => dialog_group_stub.first.id)
expect(dialog_field_association_stub.count).to eq(0)

migrate

expect(dialog_field_association_stub.count).to eq(0)
end

it "only creates dialog associations if the fields are on the same dialog" do
dialog_field_stub.create!(:name => "dialog_field4", :trigger_auto_refresh => true, :position => 4, :dialog_group_id => dialog_group_stub.first.id, :type => "DialogFieldDateControl")

expect(dialog_field_association_stub.count).to eq(0)

migrate

expect(dialog_field_association_stub.count).to eq(0)
end
end

migration_context :down do
it "should delete dialog field associations" do
dialog_field_stub.create!(:name => "dialog_field6")
dialog_field_stub.create!(:name => "dialog_field9")
dialog_field_association_stub.create!(:trigger_id => dialog_field_stub.first.id, :respond_id => dialog_field_stub.second.id)

expect(dialog_field_association_stub.count).to eq(1)

migrate

expect(dialog_field_association_stub.count).to eq(0)
end
end
end

0 comments on commit a860e35

Please sign in to comment.