#-- encoding: UTF-8 #-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2018 the OpenProject Foundation (OPF) # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License version 3. # # OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: # Copyright (C) 2006-2017 Jean-Philippe Lang # Copyright (C) 2010-2013 the ChiliProject Team # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # See docs/COPYRIGHT.rdoc for more details. #++ module Migration module Utils UpdateResult = Struct.new(:row, :updated) def say_with_time_silently(message) say_with_time message do suppress_messages do yield end end end def filter(columns, terms) column_filters = [] columns.each do |column| filters = terms.map { |term| "#{column} LIKE '%#{term}%'" } column_filters << "(#{filters.join(' OR ')})" end column_filters.join(' OR ') end def update_column_values(table, column_list, updater, conditions) update_column_values_and_journals(table, column_list, updater, false, conditions) end def update_column_values_and_journals(table, column_list, updater, update_journal, conditions) processed_rows = [] select_rows_from_database(table, column_list, conditions).each do |row| processed_rows << updater.call(row) end updated_rows = processed_rows.select(&:updated) update_rows_in_database(table, column_list, updated_rows.map(&:row)) update_journals(table, updated_rows) if update_journal end def reset_public_key_sequence_in_postgres(table) return unless ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'postgresql' ActiveRecord::Base.connection.reset_pk_sequence!(table) end def postgres? ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'postgresql' end def mysql? ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'mysql2' end private def select_rows_from_database(table, column_list, conditions) columns = (column_list.nil?) ? '' : ', ' + column_list.join(', ') from_clause = table where_clause = conditions.nil? ? '1 = 1' : conditions select_all <<-SQL SELECT id#{columns} FROM #{from_clause} WHERE #{where_clause} SQL end def update_rows_in_database(table, column_list, updated_rows) columns = (column_list.nil?) ? '' : column_list.join(', ') updated_rows.each do |row| values = column_list.map { |c| "#{c}=#{quote(row[c])}" } .join(', ') update <<-SQL UPDATE #{table} SET #{values} WHERE id = #{row['id']} SQL end end def update_journals(table, updated_rows) created_journals = {} updated_ids = updated_rows.map { |r| r.row['id'] } journal_table = "#{table.singularize}_journals" journable_type = table.classify updated_ids.each do |id| created_journals[id] = insert <<-SQL INSERT INTO journals (journable_id, journable_type, user_id, created_at, version, activity_type) SELECT journable_id, journable_type, #{system_user_id}, NOW(), MAX(version) + 1, activity_type FROM journals WHERE journable_type = '#{journable_type}' AND journable_id = #{id} GROUP BY journable_id, journable_type, activity_type SQL end journal_table_columns = journal_table_columns(journal_table) insert <<-SQL INSERT INTO #{journal_table} (journal_id, #{journal_table_columns.join(', ')}) SELECT j.id AS journal_id, #{journal_table_columns.map { |c| "w.#{c}" }.join(', ')} FROM journals AS j JOIN #{table} AS w ON (j.journable_id = w.id) WHERE journable_type = '#{journable_type}' AND j.id NOT IN (SELECT journal_id FROM work_package_journals) SQL end def system_user_id @system_user_id ||= User.system.id end def journal_table_columns(table) "Journal::#{table.classify}".constantize.column_names - ['id', 'journal_id'] end end end