From ab5eb37e91c25ac851318dda8d21a582655222da Mon Sep 17 00:00:00 2001 From: Emili Parreno Date: Thu, 5 Feb 2009 00:16:52 +0100 Subject: [PATCH] Add :limit parameter to add_index method to specify index length. Version 2 with schema dump support and more tests. --- .../abstract/schema_definitions.rb | 2 +- .../abstract/schema_statements.rb | 18 +++++++++++++++ .../connection_adapters/mysql_adapter.rb | 23 ++++++++++++++++++- activerecord/lib/active_record/schema_dumper.rb | 3 +- .../test/cases/active_schema_test_mysql.rb | 8 +++++++ activerecord/test/cases/migration_test.rb | 8 +++++++ 6 files changed, 58 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 273f823..ea0b0c8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -255,7 +255,7 @@ module ActiveRecord end end - class IndexDefinition < Struct.new(:table, :name, :unique, :columns) #:nodoc: + class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :limits) #:nodoc: end # Abstract representation of a column definition. Instances of this type diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index c29c156..cb7d0d3 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -258,6 +258,24 @@ module ActiveRecord # add_index(:accounts, [:branch_id, :party_id], :unique => true, :name => 'by_branch_party') # generates # CREATE UNIQUE INDEX by_branch_party ON accounts(branch_id, party_id) + # ====== Creating an index with specific key length + # Note: SQLite doesn't support index length + # + # add_index(:accounts, :name, :name => 'by_name', :limit => 10) + # generates + # CREATE INDEX by_name ON accounts(name(10)) + # generates + # CREATE INDEX by_name_surname ON accounts(name(10), surname(10)) + # + # add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :limit => {:name => 10, :surname => 20}) + # add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :limit => {:name => 10}) + # generates + # CREATE INDEX by_name_surname ON accounts(name(10), surname) + # + # add_index(:accounts, [:name, :surname], :name => 'by_name_surname', :limit => {:name => 10, :surname => 15}) + # generates + # CREATE INDEX by_name_surname ON accounts(name(10), surname(20)) + # CREATE INDEX by_name_surname ON accounts(name(10), surname(15)) def add_index(table_name, column_name, options = {}) column_names = Array(column_name) index_name = index_name(table_name, :column => column_names) diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 9300df2..9275300 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -442,7 +442,25 @@ module ActiveRecord def drop_table(table_name, options = {}) super(table_name, options) end - + + def add_index(table_name, column_name, options = {}) + column_names = Array(column_name) + index_name = index_name(table_name, :column => column_names) + if Hash === options # legacy support, since this param was a string + index_type = options[:unique] ? "UNIQUE" : "" + index_name = options[:name] || index_name + if Hash === options[:limit] + quoted_column_names = column_names.map {|e| (options[:limit][e] ? "#{quote_column_name(e)}(#{options[:limit][e]})" : "#{quote_column_name(e)}")}.join(", ") + elsif options[:limit] + quoted_column_names = column_names.map {|e| "#{quote_column_name(e)}(#{options[:limit]})"}.join(", ") + end + else + index_type = options + end + quoted_column_names ||= column_names.map { |e| quote_column_name(e) }.join(", ") + execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})" + end + def indexes(table_name, name = nil)#:nodoc: indexes = [] current_index = nil @@ -451,10 +469,11 @@ module ActiveRecord if current_index != row[2] next if row[2] == "PRIMARY" # skip the primary key current_index = row[2] - indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", []) + indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [], []) end indexes.last.columns << row[4] + indexes.last.limits << row[7] end result.free indexes diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index 557a554..57c7ad7 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -167,7 +167,8 @@ HEADER statment_parts << index.columns.inspect statment_parts << (':name => ' + index.name.inspect) statment_parts << ':unique => true' if index.unique - + statment_parts << (':limit => ' + Hash[*index.columns.zip(index.limits).flatten].inspect) if index.limits + ' ' + statment_parts.join(', ') end diff --git a/activerecord/test/cases/active_schema_test_mysql.rb b/activerecord/test/cases/active_schema_test_mysql.rb index 9aff538..94d2434 100644 --- a/activerecord/test/cases/active_schema_test_mysql.rb +++ b/activerecord/test/cases/active_schema_test_mysql.rb @@ -15,6 +15,14 @@ class ActiveSchemaTest < ActiveRecord::TestCase end end + def test_add_index + assert_equal "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`)", add_index(:people, :last_name, :limit => nil) + assert_equal "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`(10))", add_index(:people, :last_name, :limit => 10) + assert_equal "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(15))", add_index(:people, [:last_name, :first_name], :limit => 15) + assert_equal "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`)", add_index(:people, [:last_name, :first_name], :limit => {:last_name => 15}) + assert_equal "CREATE INDEX `index_people_on_last_name_and_first_name` ON `people` (`last_name`(15), `first_name`(10))", add_index(:people, [:last_name, :first_name], :limit => {:last_name => 15, :first_name => 10}) + end + def test_drop_table assert_equal "DROP TABLE `people`", drop_table(:people) end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 1c974e4..d9c9217 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -74,6 +74,14 @@ if ActiveRecord::Base.connection.supports_migrations? assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") } assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) } assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) } + assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :limit => 10) } + assert_nothing_raised { Person.connection.remove_index("people", "last_name") } + assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :limit => {:last_name => 10}) } + assert_nothing_raised { Person.connection.remove_index("people", ["last_name"]) } + assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :limit => 10) } + assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) } + assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :limit => {:last_name => 10, :first_name => 20}) } + assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) } end # quoting -- 1.6.0.2