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



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

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



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

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



33
34
35
36
37
# File 'lib/monkey_patch_postgres.rb', line 33

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



95
96
97
98
99
100
# File 'lib/monkey_patch_postgres.rb', line 95

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



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

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



56
57
58
59
# File 'lib/monkey_patch_postgres.rb', line 56

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



19
20
21
# File 'lib/monkey_patch_postgres.rb', line 19

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.



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

def prefetch_primary_key?(table_name)
  return false
end