Changeset 2312
- Timestamp:
- 09/23/05 13:29:33 (5 years ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb (modified) (4 diffs)
- trunk/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb (modified) (1 diff)
- trunk/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/schema_dumper.rb (added)
- trunk/activerecord/lib/active_record/schema.rb (added)
- trunk/activerecord/test/adapter_test.rb (added)
- trunk/activerecord/test/ar_schema_test.rb (added)
- trunk/activerecord/test/migration_test.rb (modified) (2 diffs)
- trunk/activerecord/test/schema_dumper_test.rb (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r2285 r2312 1 1 *SVN* 2 3 * Add ActiveRecord::SchemaDumper for dumping a DB schema to a pure-ruby file, making it easier to consolidate large migration lists and port database schemas between databases. 2 4 3 5 * Fixed migrations for Windows when using more than 10 [David Naseby] trunk/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
r2215 r2312 153 153 module ConnectionAdapters # :nodoc: 154 154 class Column # :nodoc: 155 attr_reader :name, :default, :type, :limit 155 attr_reader :name, :default, :type, :limit, :null 156 156 # The name should contain the name of the column, such as "name" in "name varchar(250)" 157 157 # The default should contain the type-casted default of the column, such as 1 in "count int(11) DEFAULT 1" 158 158 # The type parameter should either contain :integer, :float, :datetime, :date, :text, or :string 159 159 # The sql_type is just used for extracting the limit, such as 10 in "varchar(10)" 160 def initialize(name, default, sql_type = nil )161 @name, @default, @type = name, type_cast(default), simplified_type(sql_type)160 def initialize(name, default, sql_type = nil, null = true) 161 @name, @default, @type, @null = name, type_cast(default), simplified_type(sql_type), null 162 162 @limit = extract_limit(sql_type) unless sql_type.nil? 163 163 end … … 276 276 def select_one(sql, name = nil) end 277 277 278 # Returns an array of table names for the current database. 279 def tables(name = nil) end 280 281 # Returns an array of indexes for the given table. 282 def indexes(table_name, name = nil) end 283 278 284 # Returns an array of column objects for the table specified by +table_name+. 279 285 def columns(table_name, name = nil) end … … 424 430 end 425 431 426 def add_index(table_name, column_name, index_type = '') 427 execute "CREATE #{index_type} INDEX #{table_name}_#{column_name.to_a.first}_index ON #{table_name} (#{column_name.to_a.join(", ")})" 428 end 429 430 def remove_index(table_name, column_name) 431 execute "DROP INDEX #{table_name}_#{column_name}_index ON #{table_name}" 432 # Create a new index on the given table. By default, it will be named 433 # <code>"#{table_name}_#{column_name.to_a.first}_index"</code>, but you 434 # can explicitly name the index by passing <code>:name => "..."</code> 435 # as the last parameter. Unique indexes may be created by passing 436 # <code>:unique => true</code>. 437 def add_index(table_name, column_name, options = {}) 438 index_name = "#{table_name}_#{column_name.to_a.first}_index" 439 440 if Hash === options # legacy support, since this param was a string 441 index_type = options[:unique] ? "UNIQUE" : "" 442 index_name = options[:name] || index_name 443 else 444 index_type = options 445 end 446 447 execute "CREATE #{index_type} INDEX #{index_name} ON #{table_name} (#{column_name.to_a.join(", ")})" 448 end 449 450 # Remove the given index from the table. 451 # 452 # remove_index :my_table, :column => :foo 453 # remove_index :my_table, :name => :my_index_on_foo 454 # 455 # The first version will remove the index named 456 # <code>"#{my_table}_#{column}_index"</code> from the table. The 457 # second removes the named column from the table. 458 def remove_index(table_name, options = {}) 459 if Hash === options # legacy support 460 if options[:column] 461 index_name = "#{table_name}_#{options[:column]}_index" 462 elsif options[:name] 463 index_name = options[:name] 464 else 465 raise ArgumentError, "You must specify the index name" 466 end 467 else 468 index_name = "#{table_name}_#{options}_index" 469 end 470 471 execute "DROP INDEX #{index_name} ON #{table_name}" 432 472 end 433 473 … … 505 545 end 506 546 547 class IndexDefinition < Struct.new(:table, :name, :unique, :columns) 548 end 549 507 550 class ColumnDefinition < Struct.new(:base, :name, :type, :limit, :default, :null) 508 551 def to_sql trunk/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
r1912 r2312 103 103 end 104 104 105 def tables(name = nil) 106 tables = [] 107 execute("SHOW TABLES", name).each { |field| tables << field[0] } 108 tables 109 end 110 111 def indexes(table_name, name = nil) 112 indexes = [] 113 current_index = nil 114 execute("SHOW KEYS FROM #{table_name}", name).each do |row| 115 if current_index != row[2] 116 next if row[2] == "PRIMARY" # skip the primary key 117 current_index = row[2] 118 indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", []) 119 end 120 121 indexes.last.columns << row[4] 122 end 123 indexes 124 end 125 105 126 def columns(table_name, name = nil) 106 127 sql = "SHOW FIELDS FROM #{table_name}" 107 128 columns = [] 108 execute(sql, name).each { |field| columns << Column.new(field[0], field[4], field[1] ) }129 execute(sql, name).each { |field| columns << Column.new(field[0], field[4], field[1], field[2] == "YES") } 109 130 columns 110 131 end trunk/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
r1955 r2312 151 151 def rollback_db_transaction() @connection.rollback end 152 152 153 154 def tables 155 execute('.table').map { |table| Table.new(table) } 153 def tables(name = nil) 154 execute("SELECT name FROM sqlite_master WHERE type = 'table'", name).map do |row| 155 row[0] 156 end 156 157 end 157 158 158 159 def columns(table_name, name = nil) 159 160 table_structure(table_name).map { |field| 160 SQLiteColumn.new(field['name'], field['dflt_value'], field['type'] )161 SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'] == "0") 161 162 } 163 end 164 165 def indexes(table_name, name = nil) 166 execute("PRAGMA index_list(#{table_name})", name).map do |row| 167 index = IndexDefinition.new(table_name, row['name']) 168 index.unique = row['unique'] != '0' 169 index.columns = execute("PRAGMA index_info(#{index.name})").map { |col| col['name'] } 170 index 171 end 162 172 end 163 173 … … 220 230 returning structure = execute("PRAGMA table_info(#{table_name})") do 221 231 raise ActiveRecord::StatementInvalid if structure.empty? 222 end223 end224 225 def indexes(table_name)226 execute("PRAGMA index_list(#{table_name})").map do |index|227 index_info = execute("PRAGMA index_info(#{index['name']})")228 {229 :name => index['name'],230 :unique => index['unique'].to_i == 1,231 :columns => index_info.map {|info| info['name']}232 }233 232 end 234 233 end trunk/activerecord/test/migration_test.rb
r1955 r2312 33 33 def test_add_index 34 34 Person.connection.add_column "people", "last_name", :string 35 Person.connection.add_column "people", "administrator", :boolean 35 36 36 37 assert_nothing_raised { Person.connection.add_index("people", "last_name") } … … 39 40 assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) } 40 41 assert_nothing_raised { Person.connection.remove_index("people", "last_name") } 42 43 assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") } 44 assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") } 41 45 end 42 46