class PgPartitionManager::Time

Public Class Methods

new(partition, start: Date.today, db: nil) click to toggle source
# File lib/pg_partition_manager.rb, line 9
def initialize(partition, start: Date.today, db: nil)
  raise ArgumentError, "Period must be 'month', 'week', or 'day'" unless ["month", "week", "day"].include?(partition[:period])

  @partition = partition
  @start =
    case partition[:period]
     when "month"
       start - start.day + 1 # First day of the current month
     when "week"
       start - (start.cwday - 1) # First calendar day of the current week
     when "day"
       start
    end
  @db = db || PG.connect(ENV["DATABASE_URL"])
end
process(partitions) click to toggle source

A convenience method for doing all the maintenance for a list of partitions

# File lib/pg_partition_manager.rb, line 82
def self.process(partitions)
  partitions.each do |part|
    pm = new(part)
    pm.drop_tables
    pm.create_tables
  end
end

Public Instance Methods

create_tables() click to toggle source

Create tables to hold future data

# File lib/pg_partition_manager.rb, line 40
def create_tables
  schema, table = @partition[:parent_table].split(".")
  start = @start
  stop = period_end(start)

  # Note that this starts in the *current* period, so we start at 0 rather
  # than 1 for the range, to be sure the current period gets a table *and*
  # we make the number of desired future tables
  (0..(@partition[:premake] || 4)).map do |month|
    child_table = "#{schema}.#{table}_p#{start.to_s.tr("-", "_")}"
    @db.exec("create table if not exists #{child_table} partition of #{schema}.#{table} for values from ('#{start}') to ('#{stop}')")
    start = stop
    stop = period_end(start)
    child_table
  end
end
drop_tables() click to toggle source

Drop the tables that contain data that should be expired based on the retention period

# File lib/pg_partition_manager.rb, line 27
def drop_tables
  schema, table = @partition[:parent_table].split(".")
  table_suffix = retention.to_s.tr("-", "_")

  result = @db.exec("select nspname, relname from pg_class c inner join pg_namespace n on n.oid = c.relnamespace where nspname = '#{schema}' and relname like '#{table}_p%' and relkind = 'r' and relname < '#{table}_p#{table_suffix}' order by 1, 2")
  result.map do |row|
    child_table = "#{row["nspname"]}.#{row["relname"]}"
    @db.exec("drop table if exists #{child_table}")
    child_table
  end
end
period_end(start) click to toggle source

Return the begin and end dates for the next partition range

# File lib/pg_partition_manager.rb, line 70
def period_end(start)
  case @partition[:period]
  when "month"
    start >> 1
  when "week"
    start + 7
  when "day"
    start + 1
  end
end
retention() click to toggle source

Return the date for the oldest table to keep, based on the retention setting

# File lib/pg_partition_manager.rb, line 58
def retention
  case @partition[:period]
  when "month"
    @start << @partition[:retain] || 6 # Default to 6 months
  when "week"
    @start - ((@partition[:retain] || 4) * 7) # Default to 4 weeks
  when "day"
    @start - (@partition[:retain] || 7) # Default to 7 days
  end
end