Merge pull request #546 from opf/migration/timelines

[MIGRATION] Timelines
pull/542/head
ulferts 11 years ago
commit e38d335738
  1. 33
      db/migrate/20131015064141_migrate_timelines_end_date_property_in_options.rb
  2. 157
      db/migrate/20131024140048_migrate_timelines_options.rb
  3. 4
      db/migrate/migration_utils/attachable_utils.rb
  4. 66
      db/migrate/migration_utils/timelines.rb
  5. 55
      lib/tasks/remove_timelines_historical_comparison_from_options.rake

@ -9,9 +9,7 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'yaml'
require_relative 'migration_utils/utils'
require_relative 'migration_utils/timelines'
class MigrateTimelinesEndDatePropertyInOptions < ActiveRecord::Migration
include Migration::Utils
@ -26,7 +24,7 @@ class MigrateTimelinesEndDatePropertyInOptions < ActiveRecord::Migration
say_with_time_silently "Update timelines options" do
update_column_values('timelines',
[COLUMN],
update_options(OPTIONS),
update_options(migrate_end_date_options(OPTIONS)),
options_filter(OPTIONS.keys))
end
end
@ -35,7 +33,7 @@ class MigrateTimelinesEndDatePropertyInOptions < ActiveRecord::Migration
say_with_time_silently "Restore timelines options" do
update_column_values('timelines',
[COLUMN],
update_options(OPTIONS.invert),
update_options(migrate_end_date_options(OPTIONS.invert)),
options_filter(OPTIONS.invert.keys))
end
end
@ -46,28 +44,11 @@ class MigrateTimelinesEndDatePropertyInOptions < ActiveRecord::Migration
filter([COLUMN], options)
end
def update_options(options)
Proc.new do |row|
timelines_opts = YAML.load(row[COLUMN])
renamed_options = timelines_opts.each_with_object({}) do |(k, v), h|
new_key = (options.has_key? k) ? options[k] : k
h[new_key] = update_option_value(v)
end
row[COLUMN] = YAML.dump(renamed_options)
UpdateResult.new(row, true)
end
end
def migrate_end_date_options(options)
Proc.new do |timelines_opts|
opts = rename_columns(timelines_opts, options)
def update_option_value(value)
if value.kind_of? Array
value.map{|e| (OPTIONS.has_key? e) ? OPTIONS[e] : e}
elsif OPTIONS.has_key? value
OPTIONS[value]
else
value
opts
end
end
end

@ -0,0 +1,157 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require_relative 'migration_utils/timelines'
class MigrateTimelinesOptions < ActiveRecord::Migration
include Migration::Utils
COLUMN = 'options'
OPTIONS = {
# already done in 20131015064141_migrate_timelines_end_date_property_in_options.rb
#'end_date' => 'due_date',
'planning_element_types' => 'type',
'project_type' => 'type',
'project_status' => 'status',
}
def up
say_with_time_silently "Check for historical comparisons" do
comparisons = timelines_with_historical_comparisons
unless comparisons.empty?
affected_ids = comparisons.collect(&:id)
raise "Error: Cannot migrate timelines options!"\
"\n\n"\
"Timelines exist that use historical comparison. This is not\n"\
"supported in future versions of timelines.\n\n"\
"The affected timelines ids are: #{affected_ids}\n\n"\
"You may use the rake task "\
"'migrations:timelines:remove_timelines_historical_comparison_from_options' "\
"to prepare the\n"\
"current schema for this migration."\
"\n\n\n"
end
end
say_with_time_silently "Update timelines options" do
update_column_values('timelines',
[COLUMN],
update_options(migrate_timelines_options(OPTIONS,
pe_id_map,
pe_type_id_map)),
nil)
end
end
def down
say_with_time_silently "Restore timelines options" do
update_column_values('timelines',
[COLUMN],
update_options(migrate_timelines_options(OPTIONS.invert,
pe_id_map.invert,
pe_type_id_map.invert)),
nil)
end
end
private
PE_TYPE_KEY = 'planning_element_types'
PE_TIME_TYPE_KEY = 'planning_element_time_types'
VERTICAL_PE_TYPES = 'vertical_planning_elements'
def migrate_timelines_options(options, pe_id_map, pe_type_id_map)
Proc.new do |timelines_opts|
timelines_opts = rename_columns timelines_opts, options
timelines_opts = migrate_planning_element_types timelines_opts, pe_type_id_map
timelines_opts = migrate_planning_element_time_types timelines_opts, pe_type_id_map
timelines_opts = migrate_vertical_planning_elements timelines_opts, pe_id_map
timelines_opts
end
end
def migrate_planning_element_types(timelines_opts, pe_type_id_map)
pe_types = []
pe_types = timelines_opts[PE_TYPE_KEY].delete_if { |t| t.nil? } if timelines_opts.has_key? PE_TYPE_KEY
pe_types = pe_types.empty? ? new_ids_of_former_pes
: pe_types.map { |p| pe_type_id_map[p] }
timelines_opts[PE_TYPE_KEY] = pe_types
timelines_opts
end
def migrate_planning_element_time_types(timelines_opts, pe_type_id_map)
return timelines_opts unless timelines_opts.has_key? PE_TIME_TYPE_KEY
pe_time_types = timelines_opts[PE_TIME_TYPE_KEY]
pe_time_types.map! { |p| pe_type_id_map[p] }
timelines_opts[PE_TIME_TYPE_KEY] = pe_time_types
timelines_opts
end
def migrate_vertical_planning_elements(timelines_opts, pe_id_map)
return timelines_opts unless timelines_opts.has_key? VERTICAL_PE_TYPES
vertical_pes = timelines_opts[VERTICAL_PE_TYPES].split(',')
.map { |p| p.strip }
unless vertical_pes.empty?
mapped_pes = vertical_pes.map { |v| pe_id_map[v] }
.compact
timelines_opts[VERTICAL_PE_TYPES] = mapped_pes.join(',')
end
timelines_opts
end
def new_ids_of_former_pes
@new_ids_of_former_pes ||= pe_types_ids_with_new_ids.each_with_object([]) do |i, l|
l << i['new_id']
end
end
def pe_type_id_map
@pe_type_id_map ||= pe_types_ids_with_new_ids.each_with_object({}) do |r, h|
h[r['id']] = r['new_id']
end
end
def pe_types_ids_with_new_ids
select_all <<-SQL
SELECT id, new_id
FROM legacy_planning_element_types
SQL
end
def pe_id_map
@pe_id_map ||= pe_ids_with_new_ids.each_with_object({}) do |r, h|
h[r['id']] = r['new_id']
end
end
def pe_ids_with_new_ids
select_all <<-SQL
SELECT id, new_id
FROM legacy_planning_elements
SQL
end
end

@ -64,12 +64,12 @@ module Migration
COLUMNS,
find_work_packages_with_missing_initial_attachment(legacy_journal_type,
result),
filter(legacy_journal_type))
journal_filter(legacy_journal_type))
result.flatten
end
def filter(legacy_journal_type)
def journal_filter(legacy_journal_type)
"type = '#{legacy_journal_type}' AND changed_data LIKE '%attachments%'"
end

@ -0,0 +1,66 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'yaml'
require_relative 'utils'
module Migration
module Utils
TimelineWithHistoricalComparison = Struct.new(:id, :from_date, :to_date)
OPTIONS_COLUMN = 'options'
HISTORICAL_DATE_FROM = 'compare_to_historical_one'
HISTORICAL_DATE_TO = 'compare_to_historical_two'
def timelines_with_historical_comparisons
timelines = select_all <<-SQL
SELECT id, options
FROM timelines
WHERE options LIKE '%comparison: historical%'
SQL
timelines.each_with_object([]) do |r, l|
options = YAML.load(r[OPTIONS_COLUMN])
from_date = options[HISTORICAL_DATE_FROM]
to_date = options[HISTORICAL_DATE_TO]
l << TimelineWithHistoricalComparison.new(r['id'], from_date, to_date)
end
end
def update_options(callback)
Proc.new do |row|
timelines_opts = YAML.load(row[OPTIONS_COLUMN])
migrated_options = callback.call(timelines_opts.clone) unless callback.nil?
row[OPTIONS_COLUMN] = YAML.dump(HashWithIndifferentAccess.new(migrated_options))
UpdateResult.new(row, true)
end
end
def rename_columns(timelines_opts, options)
return timelines_opts unless timelines_opts.has_key? 'columns'
columns = timelines_opts['columns']
columns.map! do |c|
options.has_key?(c) ? options[c] : c
end
timelines_opts['columns'] = columns.uniq
timelines_opts
end
end
end

@ -0,0 +1,55 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require_relative '../../db/migrate/migration_utils/timelines'
namespace :migrations do
namespace :timelines do
desc "Sets all timelines with historical comparison from 'historical' to 'none'"
task :remove_timelines_historical_comparison_from_options => :environment do |task|
setter = TimelinesHistoricalComparisonSetter.new
setter.remove_timelines_historical_comparison_from_options
end
private
class TimelinesHistoricalComparisonSetter < ActiveRecord::Migration
include Migration::Utils
def remove_timelines_historical_comparison_from_options
say_with_time_silently "Set historical comparison to none for all timelines" do
update_column_values('timelines',
['options'],
update_options(set_historical_comparison_to_none),
historical_comparison_filter)
end
end
private
def set_historical_comparison_to_none
Proc.new do |timelines_opts|
timelines_opts['comparison'] = 'none'
timelines_opts
end
end
def historical_comparison_filter
"options LIKE '%comparison: historical%'"
end
end
end
end
Loading…
Cancel
Save