Return PostgreSQL columns in the order they are declared #1374 (perlguy@gmail.com). Unit test column order, adapter housekeeping, simplify users of columns_hash.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1405 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
Jeremy Kemper 2005-06-12 06:56:51 +00:00
parent 3cb26e9cb3
commit d0bd3b5af4
5 changed files with 34 additions and 30 deletions

@ -1,5 +1,7 @@
*SVN*
* Return PostgreSQL columns in the order they were declared #1374 [perlguy@gmail.com]
* Allow before/after update hooks to work on models using optimistic locking
* Eager loading of dependent has_one associations won't delete the association #1212

@ -617,9 +617,9 @@ def columns
def columns_hash
@columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
end
def column_names
@column_names ||= columns_hash.keys
@column_names ||= columns.map { |column| column.name }
end
# Returns an array of columns objects where the primary id, all columns ending in "_id" or "_count",
@ -632,7 +632,7 @@ def content_columns
# and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
# is available.
def column_methods_hash
@dynamic_methods_hash ||= columns_hash.keys.inject(Hash.new(false)) do |methods, attr|
@dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
methods[attr.to_sym] = true
methods["#{attr}=".to_sym] = true
methods["#{attr}?".to_sym] = true
@ -1293,16 +1293,14 @@ def attributes_protected_by_default
# Returns copy of the attributes hash where all the values have been safely quoted for use in
# an SQL statement.
def attributes_with_quotes(include_primary_key = true)
columns_hash = self.class.columns_hash
attrs_quoted = attributes.inject({}) do |attrs_quoted, pair|
attrs_quoted[pair.first] = quote(pair.last, columns_hash[pair.first]) unless !include_primary_key && pair.first == self.class.primary_key
attrs_quoted
attributes.inject({}) do |quoted, (name, value)|
if column = column_for_attribute(name)
quoted[name] = quote(value, column) unless !include_primary_key && name == self.class.primary_key
end
quoted
end
attrs_quoted.delete_if { |key, value| !self.class.columns_hash.keys.include?(key) }
end
# Quote strings appropriately for SQL statements.
def quote(value, column = nil)
connection.quote(value, column)

@ -78,19 +78,21 @@ def columns(table_name, name = nil)
end
def insert(sql, name = nil, pk = nil, id_value = nil)
execute(sql, name = nil)
execute(sql, name)
table = sql.split(" ", 4)[2]
return id_value || last_insert_id(table, pk)
end
def query(sql, name = nil)
log(sql, name) { @connection.query(sql) }
end
def execute(sql, name = nil)
log(sql, name, @connection) { |connection| connection.query(sql) }
log(sql, name) { @connection.exec(sql) }
end
def update(sql, name = nil)
result = nil
log(sql, name, @connection) { |connection| result = connection.exec(sql) }
result.cmdtuples
execute(sql, name).cmdtuples
end
alias_method :delete, :update
@ -122,9 +124,7 @@ def last_insert_id(table, column = "id")
end
def select(sql, name = nil)
res = nil
log(sql, name, @connection) { |connection| res = connection.exec(sql) }
res = execute(sql, name)
results = res.result
rows = []
if results.length > 0
@ -169,23 +169,22 @@ def split_table_schema(table_name)
def table_structure(table_name)
database_name = @connection.db
schema_name, table_name = split_table_schema(table_name)
# Grab a list of all the default values for the columns.
sql = "SELECT column_name, column_default, character_maximum_length, data_type "
sql << " FROM information_schema.columns "
sql << " WHERE table_catalog = '#{database_name}' "
sql << " AND table_schema = '#{schema_name}' "
sql << " AND table_name = '#{table_name}';"
sql << " AND table_name = '#{table_name}'"
sql << " ORDER BY ordinal_position"
column_defaults = nil
log(sql, nil, @connection) { |connection| column_defaults = connection.query(sql) }
column_defaults.collect do |row|
field = row[0]
type = type_as_string(row[3], row[2])
default = default_value(row[1])
length = row[2]
query(sql).collect do |row|
field = row[0]
type = type_as_string(row[3], row[2])
default = default_value(row[1])
length = row[2]
[field, type, default, length]
[field, type, default, length]
end
end

@ -50,10 +50,10 @@ CREATE TABLE topics (
bonus_time time,
last_read date,
content text,
approved smallint DEFAULT 1,
replies_count integer default 0,
parent_id integer,
"type" character varying(50),
approved smallint DEFAULT 1,
PRIMARY KEY (id)
);
SELECT setval('topics_id_seq', 100);

@ -22,6 +22,11 @@ def test_columns
assert_equal 12, Topic.columns.length
end
def test_columns_are_returned_in_the_order_they_were_declared
column_names = Topic.columns.map { |column| column.name }
assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content approved replies_count parent_id type), column_names
end
def test_content_columns
assert_equal 8, Topic.content_columns.length
end