Class: ActiveRecord::ConnectionAdapters::PostgreSQLAdapter

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

Overview

Patches extending the postgres adapter with new operations for managing sequences (and sets of sequence values), schemas and foreign keys. These should go into AbstractAdapter allowing any database adapter to take advantage of these SQL builders.

Instance Method Summary collapse

Instance Method Details

#add_foreign_key(referencing_table_name, referencing_field_name, referenced_table_name, referenced_field_name = :id) ⇒ optional

Add foreign key constraint to table.

Parameters:

  • referencing_table_name (String)

    the name of the table containing the foreign key

  • referencing_field_name (String)

    the name of foreign key column

  • referenced_table_name (String)

    the name of the table referenced by the foreign key

  • referenced_field_name (String) (defaults to: :id)

    (:id) the name of the column referenced by the foreign key

Returns:

  • (optional)

    undefined



123
124
125
# File 'lib/monkey_patch_postgres.rb', line 123

def add_foreign_key(referencing_table_name, referencing_field_name, referenced_table_name, referenced_field_name = :id)
  execute("ALTER TABLE #{referencing_table_name} add foreign key (#{referencing_field_name}) references #{referenced_table_name}(#{referenced_field_name})")
end

#create_schema(name, options = {}) ⇒ optional

Creates a schema given a name.

Parameters:

  • name (String)

    the name of the schema.

  • options (Hash) (defaults to: {})

    ({}) options for creating a schema

Options Hash (options):

  • :unless_exists (Boolean) — default: false

    check if schema exists.

Returns:

  • (optional)

    undefined



93
94
95
96
97
98
# File 'lib/monkey_patch_postgres.rb', line 93

def create_schema(name, options = {})
  if options[:unless_exists]
    return if execute("select count(*) from pg_namespace where nspname = '#{name}'").getvalue(0,0).to_i > 0
  end
  execute("CREATE SCHEMA #{name}")
end

#default_sequence_name(table_name, pk = nil) ⇒ Object

Returns the sequence name for a table’s primary key or some other specified key.

the default version strips off the schema name on the table (if it exists), as:

serial_sequence(table_name, pk || 'id').split('.').last

i can’t see any good reason for that – in fact, it seems completely broken – if you have a table public.foos and other.foos, you’ll fail to get the correct schema if you fetch the default schema name from model associated with other.foos



46
47
48
49
50
# File 'lib/monkey_patch_postgres.rb', line 46

def default_sequence_name(table_name, pk = nil) #:nodoc:
  serial_sequence(table_name, pk || 'id')
rescue ActiveRecord::StatementInvalid => e
  "#{table_name}_#{pk || 'id'}_seq"
end

#drop_schema(name, options = {}) ⇒ optional

Drop a schema given a name.

Parameters:

  • name (String)

    the name of the schema.

  • options (Hash) (defaults to: {})

    ({}) options for dropping a schema

Options Hash (options):

  • :if_exists (Boolean) — default: false

    check if schema exists.

  • :cascade (Boolean) — default: false

    drop dependant objects

Returns:

  • (optional)

    undefined



108
109
110
111
112
113
# File 'lib/monkey_patch_postgres.rb', line 108

def drop_schema(name, options = {})
  if options[:if_exists]
    return if execute("select count(*) from pg_namespace where nspname = '#{name}'").getvalue(0,0).to_i == 0
  end
  execute("DROP SCHEMA #{name}#{' cascade' if options[:cascade]}")
end

#next_sequence_value(sequence_name) ⇒ Integer

Get the next value in a sequence. Used on INSERT operation for partitioning like by_id because the ID is required before the insert so that the specific child table is known ahead of time.

Parameters:

  • sequence_name (String)

    the name of the sequence to fetch the next value from

Returns:

  • (Integer)

    the value from the sequence



59
60
61
# File 'lib/monkey_patch_postgres.rb', line 59

def next_sequence_value(sequence_name)
  return execute("select nextval('#{sequence_name}')").field_values("nextval").first.to_i
end

#next_sequence_values(sequence_name, batch_size) ⇒ Array<Integer>

Get the some next values in a sequence.

Parameters:

  • sequence_name (String)

    the name of the sequence to fetch the next values from

  • batch_size (Integer)

    count of values.

Returns:

  • (Array<Integer>)

    an array of values from the sequence



69
70
71
72
# File 'lib/monkey_patch_postgres.rb', line 69

def next_sequence_values(sequence_name, batch_size)
  result = execute("select nextval('#{sequence_name}') from generate_series(1, #{batch_size})")
  return result.field_values("nextval").map(&:to_i)
end

#partitioned_sql_adapter(model) ⇒ Object



32
33
34
# File 'lib/monkey_patch_postgres.rb', line 32

def partitioned_sql_adapter(model)
  return Partitioned::PartitionedBase::SqlAdapter.new(model)
end

#prefetch_primary_key?(table_name) ⇒ Boolean

Causes active resource to fetch the primary key for the table (using next_sequence_value()) just before an insert. We need the prefetch to happen but we don’t have enough information here to determine if it should happen, so Relation::insert has been modified to request of the ActiveRecord::Base derived class if it requires a prefetch.

Parameters:

  • table_name (String)

    the table name to query

Returns:

  • (Boolean)

    returns true if the table should have its primary key prefetched.



82
83
84
# File 'lib/monkey_patch_postgres.rb', line 82

def prefetch_primary_key?(table_name)
  return false
end