module Parts::PartitionAdapter

Public Instance Methods

attach_child_to(parent_table_name, child_table_name, constraint_clause, lock_timeout: 5) click to toggle source
# File lib/parts/partition_adapter.rb, line 57
    def attach_child_to(parent_table_name, child_table_name, constraint_clause, lock_timeout: 5)
      execute <<~SQL
        SET LOCAL lock_timeout TO '#{lock_timeout}s';
        ALTER TABLE #{quote_table_name(parent_table_name)}
        ATTACH PARTITION #{quote_table_name(child_table_name)}
        FOR VALUES #{constraint_clause};
      SQL
    end
attach_hash_child_to(parent_table_name, child_table_name, modulus:, remainder:, **options) click to toggle source
# File lib/parts/partition_adapter.rb, line 53
def attach_hash_child_to(parent_table_name, child_table_name, modulus:, remainder:, **options)
  attach_child_to(parent_table_name, child_table_name, hash_constraint_clause(modulus, remainder), **options)
end
attach_list_child_to(parent_table_name, child_table_name, values, **options) click to toggle source
# File lib/parts/partition_adapter.rb, line 45
def attach_list_child_to(parent_table_name, child_table_name, values, **options)
  attach_child_to(parent_table_name, child_table_name, list_constraint_clause(values), **options)
end
attach_range_child_to(parent_table_name, child_table_name, start_range:, end_range:) click to toggle source
# File lib/parts/partition_adapter.rb, line 49
def attach_range_child_to(parent_table_name, child_table_name, start_range:, end_range:)
  attach_child_to(parent_table_name, child_table_name, range_constraint_clause(start_range, end_range), **options)
end
create_hash_child_of(parent_table_name, table_name, modulus:, remainder:, **options) click to toggle source
# File lib/parts/partition_adapter.rb, line 25
def create_hash_child_of(parent_table_name, table_name, modulus:, remainder:, **options)
  create_child_of(parent_table_name, table_name, hash_constraint_clause(modulus, remainder), **options)
end
create_hash_children_of(parent_table_name, total, **options) click to toggle source
# File lib/parts/partition_adapter.rb, line 29
def create_hash_children_of(parent_table_name, total, **options)
  raise "'total' must be an Integer" unless total.is_a?(Integer)

  total.times do |t|
    create_hash_child_of(parent_table_name, "#{parent_table_name}_#{t}", modulus: total, remainder: t, **options)
  end
end
create_hash_parent(table_name, partition_key, **options, &blk) click to toggle source
# File lib/parts/partition_adapter.rb, line 13
def create_hash_parent(table_name, partition_key, **options, &blk)
  create_parent(table_name, :hash, partition_key, options, &blk)
end
create_list_child_of(parent_table_name, table_name, values, **options) click to toggle source
# File lib/parts/partition_adapter.rb, line 21
def create_list_child_of(parent_table_name, table_name, values, **options)
  create_child_of(parent_table_name, table_name, list_constraint_clause(values), **options)
end
create_list_parent(table_name, partition_key, **options, &blk) click to toggle source
# File lib/parts/partition_adapter.rb, line 9
def create_list_parent(table_name, partition_key, **options, &blk)
  create_parent(table_name, :list, partition_key, options, &blk)
end
create_range_child_of(parent_table_name, table_name, start_range:, end_range:, **options) click to toggle source
# File lib/parts/partition_adapter.rb, line 17
def create_range_child_of(parent_table_name, table_name, start_range:, end_range:, **options)
  create_child_of(parent_table_name, table_name, range_constraint_clause(start_range, end_range), **options)
end
create_range_parent(table_name, partition_key, **options, &blk) click to toggle source
# File lib/parts/partition_adapter.rb, line 5
def create_range_parent(table_name, partition_key, **options, &blk)
  create_parent(table_name, :range, partition_key, options, &blk)
end
create_sub_parent(table_name, parent_table_name:, parent_type:, parent_values:, type:, partition_key:, lock_timeout: 5) click to toggle source
# File lib/parts/partition_adapter.rb, line 66
    def create_sub_parent(table_name, parent_table_name:, parent_type:, parent_values:, type:, partition_key:, lock_timeout: 5) # rubocop:disable Metrics/ParameterLists

      constraint_clause = case parent_type
      when :list
        list_constraint_clause(parent_values)
      when :range
        range_constraint_clause(parent_values[0], parent_values[1])
      when :hash
        hash_constraint_clause(parent_values[0], parent_values[1])
      end

      execute <<~SQL
        SET LOCAL lock_timeout TO '#{lock_timeout}s';
        CREATE TABLE #{table_name} PARTITION OF #{parent_table_name} FOR VALUES #{constraint_clause} PARTITION BY #{type.to_s.upcase} (#{partition_key});
      SQL
    end
detach_child_from(parent_table_name, child_table_name, lock_timeout: 5) click to toggle source
# File lib/parts/partition_adapter.rb, line 37
    def detach_child_from(parent_table_name, child_table_name, lock_timeout: 5)
      execute <<~SQL
        SET LOCAL lock_timeout TO '#{lock_timeout}s';
        ALTER TABLE #{quote_table_name(parent_table_name)}
        DETACH PARTITION #{quote_table_name(child_table_name)};
      SQL
    end

Private Instance Methods

calculate_primary_key(table_name) click to toggle source
# File lib/parts/partition_adapter.rb, line 107
def calculate_primary_key(table_name)
  ActiveRecord::Base.get_primary_key(table_name.to_s.singularize).to_sym
end
create_child_of(parent_table_name, table_name, constraint_clause, lock_timeout: 5) click to toggle source
# File lib/parts/partition_adapter.rb, line 100
    def create_child_of(parent_table_name, table_name, constraint_clause, lock_timeout: 5)
      execute <<~SQL
        SET LOCAL lock_timeout TO '#{lock_timeout}s';
        CREATE TABLE #{table_name} PARTITION OF #{parent_table_name} FOR VALUES #{constraint_clause};
      SQL
    end
create_parent(table_name, type, partition_key, options) { |t| ... } click to toggle source
# File lib/parts/partition_adapter.rb, line 85
def create_parent(table_name, type, partition_key, options)
  options[:options] = "PARTITION BY #{type.to_s.upcase} (#{quote_partition_key(partition_key)})"
  id               = options.fetch(:id, :bigserial)
  primary_key      = options.fetch(:primary_key) { calculate_primary_key(table_name) } if id != false
  options[:id] = false

  validate_primary_key(primary_key)

  create_table(table_name, **options) do |t|
    t.column(primary_key, id, null: false) if id != false

    yield(t) if block_given?
  end
end
hash_constraint_clause(modulus, remainder) click to toggle source
# File lib/parts/partition_adapter.rb, line 135
def hash_constraint_clause(modulus, remainder)
  "WITH (MODULUS #{modulus}, REMAINDER #{remainder})"
end
list_constraint_clause(values) click to toggle source
# File lib/parts/partition_adapter.rb, line 131
def list_constraint_clause(values)
  "IN (#{quote_collection(values)})"
end
quote_collection(values) click to toggle source
# File lib/parts/partition_adapter.rb, line 123
def quote_collection(values)
  Array.wrap(values).map(&method(:quote)).join(',')
end
quote_partition_key(key) click to toggle source
# File lib/parts/partition_adapter.rb, line 115
def quote_partition_key(key)
  if key.is_a?(Proc)
    key.call.to_s
  else
    quote_column_name(key)
  end
end
range_constraint_clause(start_range, end_range) click to toggle source
# File lib/parts/partition_adapter.rb, line 127
def range_constraint_clause(start_range, end_range)
  "FROM (#{quote_collection(start_range)}) TO (#{quote_collection(end_range)})"
end
validate_primary_key(key) click to toggle source
# File lib/parts/partition_adapter.rb, line 111
def validate_primary_key(key)
  raise ArgumentError, 'composite primary key not supported' if key.is_a?(Array)
end