diff --git a/script/db_timestamps_mover.rb b/script/db_timestamps_mover.rb new file mode 100644 index 00000000000..b1afef25c43 --- /dev/null +++ b/script/db_timestamps_mover.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true +require "pg" + +usage = <<-END +Commands: + ruby db_timestamp_updater.rb yesterday move all timestamps by x days so that will be moved to yesterday + ruby db_timestamp_updater.rb 100 move all timestamps forward by 100 days + ruby db_timestamp_updater.rb -100 move all timestamps backward by 100 days +END + +class TimestampsUpdater + TABLE_SCHEMA = 'public' + + def initialize + @raw_connection = PG.connect( + host: ENV['DISCOURSE_DB_HOST'] || 'localhost', + port: ENV['DISCOURSE_DB_PORT'] || 5432, + dbname: ENV['DISCOURSE_DB_NAME'] || 'discourse_development', + user: ENV['DISCOURSE_DB_USERNAME'] || 'postgres', + password: ENV['DISCOURSE_DB_PASSWORD'] || '') + end + + def move_by(days) + postgresql_date_types = [ + "timestamp without time zone", + "timestamp with time zone", + "date" + ] + + postgresql_date_types.each do |data_type| + columns = all_columns_of_type(data_type) + columns.each do |c| + table = c["table_name"] + column = c["column_name"] + move_timestamps table, column, days + end + end + end + + def move_to_yesterday(date) + days = (Date.today.prev_day - date).to_i + move_by days + end + + private + + def all_columns_of_type(data_type) + sql = <<~SQL + SELECT c.column_name, c.table_name + FROM information_schema.columns AS c + JOIN information_schema.tables AS t + ON c.table_name = t.table_name + WHERE c.table_schema = '#{TABLE_SCHEMA}' + AND c.data_type = '#{data_type}' + AND t.table_type = 'BASE TABLE' + SQL + @raw_connection.exec(sql) + end + + def move_timestamps(table_name, column_name, days) + operator = days < 0 ? "-" : "+" + sql = <<~SQL + UPDATE #{table_name} + SET #{column_name} = #{column_name} #{operator} INTERVAL '#{days.abs} day' + SQL + @raw_connection.exec(sql) + end +end + +def is_i?(string) + true if Integer(string) rescue false +end + +def is_date?(string) + true if Date.parse(string) rescue false +end + +if ARGV.length == 2 && ARGV[0] == "yesterday" && is_date?(ARGV[1]) + date = Date.parse(ARGV[1]) + TimestampsUpdater.new.move_to_yesterday date +elsif ARGV.length == 1 && is_i?(ARGV[0]) + days = ARGV[0].to_i + TimestampsUpdater.new.move_by days +else + puts usage + exit 1 +end