scottohara/loot

View on GitHub
lib/tasks/db_shrink.rake

Summary

Maintainability
Test Coverage
# Copyright (c) 2016 Scott O'Hara, oharagroup.net
# frozen_string_literal: true

# Helper functions
module Shrink
    def progress(action, count, type)
        reset_line = "\r\e[0K"
        print "#{reset_line}#{action} #{::ActionController::Base.helpers.pluralize count, type}"
    end
end

namespace :db do
    desc 'Purge transactions earlier than [:cutoff_date] (rake db:shrink[2001-12-31])'
    task :shrink, [:cutoff_date] => :environment do |_t, args|
        abort 'You must provide a :cutoff_date as YYYY-MM-DD (eg. rake db:shrink[2001-12-31])' if args[:cutoff_date].nil?

        # Turn off verbose logging
        ::ActiveRecord::Base.logger.level = 1

        # Get the transaction headers
        transaction_headers = ::TransactionHeader.where transaction_date: ::Date.new(0)...::Date.parse(args[:cutoff_date])

        # Early exit if no transactions found
        abort "No transactions earlier than #{args[:cutoff_date]} found" if transaction_headers.size.eql? 0

        # Sanity check
        print "WARNING: You are about to purge #{::ActionController::Base.helpers.pluralize transaction_headers.size, 'transaction header'} earlier than #{args[:cutoff_date]}. Type 'purge' and hit enter to proceed: "
        abort 'Shrink aborted' if $stdin.gets.chomp.casecmp('purge').nonzero?

        subtransaction_types = %w[Subtransfer Sub]
        transaction_headers.each_with_index do |header, index|
            # Destroy the transaction
            header.trx.as_subclass.destroy! unless header.trx.nil? || subtransaction_types.include?(header.trx.transaction_type)

            index += 1
            ::Shrink.progress 'Deleted', index, 'transaction'
        end
        puts

        # Remove any categories/payees/securities that no longer have transactions
        %w[category payee security].each do |entity|
            table = (entity.eql?('category') && 'categories') || 'headers'
            where = (entity.eql?('category') && 'categories.parent_id IS NOT NULL') || ''
            entities = entity.capitalize.constantize.joins("LEFT OUTER JOIN transaction_#{table} ON transaction_#{table}.#{entity}_id = #{::ActiveSupport::Inflector.pluralize entity}.id").where(where).group(:id).having "COUNT(transaction_#{table}.transaction_id) = 0"

            next if entities.length.eql? 0

            print "Purge #{::ActionController::Base.helpers.pluralize entities.length, entity} that no longer #{::ActionController::Base.helpers.pluralize entities.length, 'has', 'have'} any transactions? (y)es or (n)o [enter = no]: "
            if $stdin.gets.chomp.casecmp('y').zero?
                entities.each_with_index do |e, index|
                    # Destroy the entity
                    e.destroy!

                    index += 1
                    ::Shrink.progress 'Deleted', index, entity
                end
            else
                print "Skipped purging #{::ActionController::Base.helpers.pluralize entities.length, entity}"
            end

            puts
        end

        puts
        puts 'Shrink done'
    end
end