class RR::ProxyConnection

This class represents a remote activerecord database connection. Normally created by DatabaseProxy

Attributes

config[RW]

A hash as described by ActiveRecord::Base#establish_connection

connection[RW]

The database connection

cursors[RW]

Hash to register cursors. Purpose:

Objects only referenced remotely via DRb can be garbage collected.
We register them in this hash to protect them from unintended garbage collection.
manual_primary_keys[RW]

A hash of manually overwritten primary keys:

  • key: table_name

  • value: array of primary key names

primary_key_names_cache[RW]

Caching the primary keys. This is a hash with

* key: table name
* value: array of primary key names
table_column_names[RW]

Hash of table_name => array of column names pairs.

table_columns[RW]

2-level Hash of table_name => column_name => Column objects.

Public Class Methods

new(config) click to toggle source

Create a session on the proxy side according to provided configuration hash. config is a hash as described by ActiveRecord::Base#establish_connection

# File lib/rubyrep/proxy_connection.rb, line 239
def initialize(config)
  self.connection = ConnectionExtenders.db_connect config
  self.config = config
  self.manual_primary_keys = {}
end

Public Instance Methods

column_names(table) click to toggle source

Returns an array of column names of the given table name. The array is ordered in the sequence as returned by the database. The result is cached for higher speed.

# File lib/rubyrep/proxy_connection.rb, line 291
def column_names(table)
  self.table_column_names ||= {}
  unless table_column_names.include? table
    table_column_names[table] = columns(table).map {|c| c.name}
  end
  table_column_names[table]
end
create_cursor(cursor_class, table, options = {}) click to toggle source

Create a cursor for the given table.

* +cursor_class+: should specify the Cursor class (e. g. ProxyBlockCursor or ProxyRowCursor).
* +table+: name of the table 
* +options+: An option hash that is used to construct the SQL query. See ProxyCursor#construct_query for details.
# File lib/rubyrep/proxy_connection.rb, line 275
def create_cursor(cursor_class, table, options = {})
  cursor = cursor_class.new self, table
  cursor.prepare_fetch options
  save_cursor cursor
  cursor
end
create_table(*params) click to toggle source

Creates a table Call forwarded to ActiveRecord::ConnectionAdapters::SchemaStatements#create_table Provides an empty block (to prevent DRB from calling back the client)

# File lib/rubyrep/proxy_connection.rb, line 183
def create_table(*params)
  connection.create_table(*params) {}
end
delete_record(table, values) click to toggle source

Deletes the specified record from the named table. values is a hash of column_name => value pairs. (Only the primary key values will be used and must be included in the hash.) Returns the number of deleted records.

# File lib/rubyrep/proxy_connection.rb, line 437
def delete_record(table, values)
  delete table_delete_query(table, values)
end
destroy() click to toggle source

Destroys the session

# File lib/rubyrep/proxy_connection.rb, line 246
def destroy
  cursors.each_key do |cursor|
    cursor.destroy
  end
  cursors.clear

  if connection.log_subscriber
    ActiveSupport::Notifications.notifier.unsubscribe connection.log_subscriber
    connection.log_subscriber = nil
  end

  self.connection.disconnect!
end
destroy_cursor(cursor) click to toggle source

Destroys the provided cursor and removes it from the register

# File lib/rubyrep/proxy_connection.rb, line 283
def destroy_cursor(cursor)
  cursor.destroy
  cursors.delete cursor
end
insert_record(table, values) click to toggle source

Inserts the specified records into the named table. values is a hash of column_name => value pairs.

# File lib/rubyrep/proxy_connection.rb, line 389
def insert_record(table, values)
  execute table_insert_query(table, values)
end
primary_key_names(table_name, options = {}) click to toggle source

Returns an array of primary key names for the given table_name. Caches the result for future calls. Allows manual overwrites through the Configuration options :primary_key_names or :primary_key_only_limit.

Parameters:

  • table_name: name of the table

  • options: An option hash with the following valid options:

    • :raw: if true, than don't use manual overwrites and don't cache

# File lib/rubyrep/proxy_connection.rb, line 168
def primary_key_names(table_name, options = {})
  return connection.primary_key_names(table_name) if options[:raw]
  
  self.primary_key_names_cache ||= {}
  result = primary_key_names_cache[table_name]
  unless result
    result = manual_primary_keys[table_name] || connection.primary_key_names(table_name)
    primary_key_names_cache[table_name] = result
  end
  result
end
quote_value(table, column, value) click to toggle source

Quotes the given value. It is assumed that the value belongs to the specified column name and table name. Caches the column objects for higher speed.

# File lib/rubyrep/proxy_connection.rb, line 262
def quote_value(table, column, value)
  self.table_columns ||= {}
  unless table_columns.include? table
    table_columns[table] = {}
    columns(table).each {|c| table_columns[table][c.name] = c}
  end
  connection.column_aware_quote value, table_columns[table][column.to_s]
end
save_cursor(cursor) click to toggle source

Store a cursor in the register to protect it from the garbage collector.

# File lib/rubyrep/proxy_connection.rb, line 193
def save_cursor(cursor)
  cursors[cursor] = cursor
end
select_cursor(options) click to toggle source

Returns a cusor as produced by the select_cursor method of the connection extenders.

Two modes of operation: Either

  • execute the specified query (takes precedense) OR

  • first build the query based on options forwarded to table_select_query

options is a hash with

  • :query: executes the given query

  • further options as taken by table_select_query to build the query

  • :row_buffer_size: Integer controlling how many rows a read into memory at one time.

# File lib/rubyrep/proxy_connection.rb, line 208
def select_cursor(options)
  cursor = ResultFetcher.new(self, options)
  cursor = TypeCastingCursor.new(self, options[:table], cursor)
  cursor
end
select_record(options) click to toggle source

Reads the designated record from the database. Refer to select_cursor for details parameter description. Returns the first matching row (column_name => value hash or nil).

# File lib/rubyrep/proxy_connection.rb, line 217
def select_record(options)
  cursor = select_cursor({:row_buffer_size => 1}.merge(options))
  row = cursor.next? ? cursor.next_row : nil
  cursor.clear
  row
end
select_records(options) click to toggle source

Reads the designated records from the database. Refer to select_cursor for details parameter description. Returns an array of matching rows (column_name => value hashes).

# File lib/rubyrep/proxy_connection.rb, line 227
def select_records(options)
  cursor = select_cursor(options)
  rows = []
  while cursor.next?
    rows << cursor.next_row
  end
  cursor.clear
  rows
end
table_delete_query(table, values) click to toggle source

Returns an SQL delete query for the given table and values values is a hash of column_name => value pairs. (Only the primary key values will be used and must be included in the hash.)

# File lib/rubyrep/proxy_connection.rb, line 425
def table_delete_query(table, values)
  query = "delete from #{quote_table_name(table)}"
  query << " where (" << quote_key_list(table) << ") = ("
  query << primary_key_names(table).map do |key|
    quote_value(table, key, values[key])
  end.join(', ') << ")"
end
table_insert_query(table, values) click to toggle source

Returns an SQL insert query for the given table and values. values is a hash of column_name => value pairs.

# File lib/rubyrep/proxy_connection.rb, line 376
def table_insert_query(table, values)
  query = "insert into #{quote_table_name(table)}"
  query << '(' << values.keys.map do |column_name|
    quote_column_name(column_name)
  end.join(', ') << ') '
  query << 'values(' << values.map do |column_name, value|
    quote_value(table, column_name, value)
  end.join(', ') << ')'
  query
end
table_select_query(table, options = {}) click to toggle source

Returns an SQL query string for the given table based on the provided options. options is a hash that can contain any of the following:

* :+from+: nil OR the hash of primary key => value pairs designating the start of the selection
* :+exclude_starting_row+: if true, do not include the row specified by :+from+
* :+to+: nil OR the hash of primary key => value pairs designating the end of the selection
* :+row_keys+: an array of primary key => value hashes specify the target rows.
# File lib/rubyrep/proxy_connection.rb, line 337
def table_select_query(table, options = {})
  query = "select #{quote_column_list(table)}"
  query << " from #{quote_table_name(table)}"
  query << " where" if [:from, :to, :row_keys].any? {|key| options.include? key}
  first_condition = true
  if options[:from]
    first_condition = false
    matching_condition = options[:exclude_starting_row] ? '>' : '>='
    query << row_condition(table, options[:from], matching_condition)
  end
  if options[:to]
    query << ' and' unless first_condition
    first_condition = false
    query << row_condition(table, options[:to], '<=')
  end
  if options[:row_keys]
    query << ' and' unless first_condition
    if options[:row_keys].empty?
      query << ' false'
    else
      query << ' (' << quote_key_list(table) << ') in ('
      first_key = true
      options[:row_keys].each do |row|
        query << ', ' unless first_key
        first_key = false
        query << '(' << primary_key_names(table).map do |key|
          quote_value(table, key, row[key])
        end.join(', ') << ')'
      end
      query << ')'
    end
  end
  query << " order by #{quote_key_list(table)}"

  query
end
table_update_query(table, values, org_key = nil) click to toggle source

Returns an SQL update query.

  • table: name of the target table

  • values: a hash of column_name => value pairs

  • org_key: A hash of column_name => value pairs. If nil, use the key specified by values instead.

# File lib/rubyrep/proxy_connection.rb, line 399
def table_update_query(table, values, org_key = nil)
  org_key ||= values
  query = "update #{quote_table_name(table)} set "
  query << values.map do |column_name, value|
    "#{quote_column_name(column_name)} = #{quote_value(table, column_name, value)}"
  end.join(', ')
  query << " where (" << quote_key_list(table) << ") = ("
  query << primary_key_names(table).map do |key|
    quote_value(table, key, org_key[key])
  end.join(', ') << ")"
end
update_record(table, values, org_key = nil) click to toggle source

Updates the specified records of the specified table.

  • table: name of the target table

  • values: a hash of column_name => value pairs.

  • org_key: A hash of column_name => value pairs. If nil, use the key specified by values instead.

Returns the number of modified records.

# File lib/rubyrep/proxy_connection.rb, line 418
def update_record(table, values, org_key = nil)
  update table_update_query(table, values, org_key)
end

Private Instance Methods

quote_column_list(table) click to toggle source

Returns a list of quoted column names for the given table as comma separated string.

# File lib/rubyrep/proxy_connection.rb, line 301
def quote_column_list(table)
  column_names(table).map do |column_name| 
    quote_column_name(column_name)
  end.join(', ')
end
quote_key_list(table) click to toggle source

Returns a list of quoted primary key names for the given table as comma separated string.

# File lib/rubyrep/proxy_connection.rb, line 310
def quote_key_list(table)
  primary_key_names(table).map do |column_name| 
    quote_column_name(column_name)
  end.join(', ')
end
row_condition(table, row, condition) click to toggle source

Generates an sql condition string for the given table based on

* +row+: a hash of primary key => value pairs designating the target row
* +condition+: the type of sql condition (something like '>=' or '=', etc.)
# File lib/rubyrep/proxy_connection.rb, line 321
def row_condition(table, row, condition)
  query_part = ""
  query_part << ' (' << quote_key_list(table) << ') ' << condition
  query_part << ' (' << primary_key_names(table).map do |key|
    quote_value(table, key, row[key])
  end.join(', ') << ')'
  query_part
end