Class: PgPartitionManager::Time

Inherits:
Object
  • Object
show all
Defined in:
lib/pg_partition_manager.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(partition, start: Date.today, db: nil) ⇒ Time

Returns a new instance of Time.

Raises:

  • (ArgumentError)


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 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

Class Method Details

.process(partitions) ⇒ Object

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



82
83
84
85
86
87
88
# 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

Instance Method Details

#create_tablesObject

Create tables to hold future data



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 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_tablesObject

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



27
28
29
30
31
32
33
34
35
36
37
# 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) ⇒ Object

Return the begin and end dates for the next partition range



70
71
72
73
74
75
76
77
78
79
# 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

#retentionObject

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



58
59
60
61
62
63
64
65
66
67
# 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