From 1dca75c2c8f930b58d86cd2216af5e14307b3e53 Mon Sep 17 00:00:00 2001 From: Greg Navis Date: Sat, 13 May 2017 03:09:58 +0200 Subject: Add support for PostgreSQL operator classes to add_index Add support for specifying non-default operator classes in PostgreSQL indexes. An example CREATE INDEX query that becomes possible is: CREATE INDEX users_name ON users USING gist (name gist_trgm_ops); Previously it was possible to specify the `gist` index but not the custom operator class. The `add_index` call for the above query is: add_index :users, :name, using: :gist, opclasses: {name: :gist_trgm_ops} --- .../adapters/postgresql/active_schema_test.rb | 3 ++ .../adapters/postgresql/postgresql_adapter_test.rb | 10 +++---- .../test/cases/adapters/postgresql/schema_test.rb | 32 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) (limited to 'activerecord/test/cases/adapters') diff --git a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb index 9929237546..99c53dadeb 100644 --- a/activerecord/test/cases/adapters/postgresql/active_schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/active_schema_test.rb @@ -59,6 +59,9 @@ class PostgresqlActiveSchemaTest < ActiveRecord::PostgreSQLTestCase assert_equal expected, add_index(:people, "lower(last_name)", using: type, unique: true) end + expected = %(CREATE INDEX "index_people_on_last_name" ON "people" USING gist ("last_name" bpchar_pattern_ops)) + assert_equal expected, add_index(:people, :last_name, using: :gist, opclass: { last_name: :bpchar_pattern_ops }) + assert_raise ArgumentError do add_index(:people, :last_name, algorithm: :copy) end diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index f199519d86..1951230c8a 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -248,12 +248,12 @@ module ActiveRecord def test_index_with_opclass with_example_table do - @connection.add_index "ex", "data varchar_pattern_ops" - index = @connection.indexes("ex").find { |idx| idx.name == "index_ex_on_data_varchar_pattern_ops" } - assert_equal "data varchar_pattern_ops", index.columns + @connection.add_index "ex", "data", opclass: "varchar_pattern_ops" + index = @connection.indexes("ex").find { |idx| idx.name == "index_ex_on_data" } + assert_equal ["data"], index.columns - @connection.remove_index "ex", "data varchar_pattern_ops" - assert_not @connection.indexes("ex").find { |idx| idx.name == "index_ex_on_data_varchar_pattern_ops" } + @connection.remove_index "ex", "data" + assert_not @connection.indexes("ex").find { |idx| idx.name == "index_ex_on_data" } end end diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index 5a64da028b..a6ae18a826 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -500,6 +500,38 @@ class SchemaForeignKeyTest < ActiveRecord::PostgreSQLTestCase end end +class SchemaIndexOpclassTest < ActiveRecord::PostgreSQLTestCase + include SchemaDumpingHelper + + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table "trains" do |t| + t.string :name + t.text :description + end + end + + teardown do + @connection.drop_table "trains", if_exists: true + end + + def test_string_opclass_is_dumped + @connection.execute "CREATE INDEX trains_name_and_description ON trains USING btree(name text_pattern_ops, description text_pattern_ops)" + + output = dump_table_schema "trains" + + assert_match(/opclass: "text_pattern_ops"/, output) + end + + def test_non_default_opclass_is_dumped + @connection.execute "CREATE INDEX trains_name_and_description ON trains USING btree(name, description text_pattern_ops)" + + output = dump_table_schema "trains" + + assert_match(/opclass: \{"description"=>"text_pattern_ops"\}/, output) + end +end + class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCase setup do @connection = ActiveRecord::Base.connection -- cgit v1.2.3 From dd6338a0699f2301d4b2fc8653688b4c4183cee5 Mon Sep 17 00:00:00 2001 From: Dinah Shi Date: Sat, 2 Dec 2017 14:30:10 +0800 Subject: Extract sql fragment generators for alter table from PostgreSQL adapter --- activerecord/test/cases/adapters/mysql2/connection_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/test/cases/adapters') diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb index e61c70848a..13b4096671 100644 --- a/activerecord/test/cases/adapters/mysql2/connection_test.rb +++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb @@ -174,10 +174,10 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase assert_equal "SCHEMA", @subscriber.logged[0][1] end - def test_logs_name_rename_column_sql + def test_logs_name_rename_column_for_alter @connection.execute "CREATE TABLE `bar_baz` (`foo` varchar(255))" @subscriber.logged.clear - @connection.send(:rename_column_sql, "bar_baz", "foo", "foo2") + @connection.send(:rename_column_for_alter, "bar_baz", "foo", "foo2") assert_equal "SCHEMA", @subscriber.logged[0][1] ensure @connection.execute "DROP TABLE `bar_baz`" -- cgit v1.2.3 From 01fb0907b2dafcecf63eedb80408d4cbff5f4d23 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sun, 3 Dec 2017 04:57:04 +0900 Subject: Refactor `length`, `order`, and `opclass` index options dumping --- activerecord/test/cases/adapters/postgresql/schema_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/test/cases/adapters') diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb index a6ae18a826..1126908761 100644 --- a/activerecord/test/cases/adapters/postgresql/schema_test.rb +++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb @@ -459,7 +459,7 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase assert_equal :btree, index_d.using assert_equal :gin, index_e.using - assert_equal :desc, index_d.orders[INDEX_D_COLUMN] + assert_equal :desc, index_d.orders end end @@ -520,7 +520,7 @@ class SchemaIndexOpclassTest < ActiveRecord::PostgreSQLTestCase output = dump_table_schema "trains" - assert_match(/opclass: "text_pattern_ops"/, output) + assert_match(/opclass: :text_pattern_ops/, output) end def test_non_default_opclass_is_dumped @@ -528,7 +528,7 @@ class SchemaIndexOpclassTest < ActiveRecord::PostgreSQLTestCase output = dump_table_schema "trains" - assert_match(/opclass: \{"description"=>"text_pattern_ops"\}/, output) + assert_match(/opclass: \{ description: :text_pattern_ops \}/, output) end end -- cgit v1.2.3 From 70fa9e9ab7fd89589664ecd7ee367448ef45f9d8 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sun, 3 Dec 2017 15:28:10 +0900 Subject: Emulate JSON types for SQLite3 adapter (#29664) Actually SQLite3 doesn't have JSON storage class (so it is stored as a TEXT like Date and Time). But emulating JSON types is convinient for making database agnostic migrations. --- activerecord/test/cases/adapters/sqlite3/json_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord/test/cases/adapters') diff --git a/activerecord/test/cases/adapters/sqlite3/json_test.rb b/activerecord/test/cases/adapters/sqlite3/json_test.rb index 568a524058..6f247fcd22 100644 --- a/activerecord/test/cases/adapters/sqlite3/json_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/json_test.rb @@ -9,8 +9,8 @@ class SQLite3JSONTest < ActiveRecord::SQLite3TestCase def setup super @connection.create_table("json_data_type") do |t| - t.column "payload", :json, default: {} - t.column "settings", :json + t.json "payload", default: {} + t.json "settings" end end -- cgit v1.2.3 From 5ac4f4d2563e7f9c5ffaecce4be4b9e2c5b0c081 Mon Sep 17 00:00:00 2001 From: Ashley Ellis Pierce Date: Mon, 4 Dec 2017 16:44:33 -0500 Subject: Fix sqlite migrations with custom primary keys Previously, if a record was created with a custom primary key, that table could not be migrated using sqlite. While attempting to copy the table, the type of the primary key was ignored. Once that was corrected, copying the indexes would fail because custom primary keys are autoindexed by sqlite by default. To correct that, this skips copying the index if the index name begins with "sqlite_". This is a reserved word that indicates that the index is an internal schema object. SQLite prohibits applications from creating objects whose names begin with "sqlite_", so this string should be safe to use as a check. ref https://www.sqlite.org/fileformat2.html#intschema --- .../cases/adapters/sqlite3/sqlite3_adapter_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'activerecord/test/cases/adapters') diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 1f057fe5c6..14f4997d5b 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -360,6 +360,24 @@ module ActiveRecord end end + class Barcode < ActiveRecord::Base + end + + def test_existing_records_have_custom_primary_key + connection = Barcode.connection + connection.create_table(:barcodes, primary_key: "code", id: :string, limit: 42, force: true) do |t| + t.text :other_attr + end + code = "214fe0c2-dd47-46df-b53b-66090b3c1d40" + Barcode.create! code: code, other_attr: "xxx" + + connection.change_table "barcodes" do |t| + connection.remove_column("barcodes", "other_attr") + end + + assert_equal code, Barcode.first.id + end + def test_supports_extensions assert_not @conn.supports_extensions?, "does not support extensions" end -- cgit v1.2.3 From 131cc6eab64eeae6c7f508dca4176183144cf3a6 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Fri, 8 Dec 2017 10:49:25 +0900 Subject: SQLite: Fix `copy_table` with composite primary keys `connection.primary_key` also return composite primary keys, so `from_primary_key_column` may not be found even if `from_primary_key` is presented. ``` % ARCONN=sqlite3 be ruby -w -Itest test/cases/adapters/sqlite3/sqlite3_adapter_test.rb -n test_copy_table_with_composite_primary_keys Using sqlite3 Run options: -n test_copy_table_with_composite_primary_keys --seed 19041 # Running: E Error: ActiveRecord::ConnectionAdapters::SQLite3AdapterTest#test_copy_table_with_composite_primary_keys: NoMethodError: undefined method `type' for nil:NilClass /path/to/rails/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb:411:in `block in copy_table' ``` This change fixes `copy_table` to do not lose composite primary keys. --- .../cases/adapters/sqlite3/sqlite3_adapter_test.rb | 31 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'activerecord/test/cases/adapters') diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 14f4997d5b..1357719422 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -361,21 +361,48 @@ module ActiveRecord end class Barcode < ActiveRecord::Base + self.primary_key = "code" end - def test_existing_records_have_custom_primary_key + def test_copy_table_with_existing_records_have_custom_primary_key connection = Barcode.connection connection.create_table(:barcodes, primary_key: "code", id: :string, limit: 42, force: true) do |t| t.text :other_attr end code = "214fe0c2-dd47-46df-b53b-66090b3c1d40" - Barcode.create! code: code, other_attr: "xxx" + Barcode.create!(code: code, other_attr: "xxx") connection.change_table "barcodes" do |t| connection.remove_column("barcodes", "other_attr") end assert_equal code, Barcode.first.id + ensure + Barcode.reset_column_information + end + + def test_copy_table_with_composite_primary_keys + connection = Barcode.connection + connection.create_table(:barcodes, primary_key: ["region", "code"], force: true) do |t| + t.string :region + t.string :code + t.text :other_attr + end + region = "US" + code = "214fe0c2-dd47-46df-b53b-66090b3c1d40" + Barcode.create!(region: region, code: code, other_attr: "xxx") + + connection.change_table "barcodes" do |t| + connection.remove_column("barcodes", "other_attr") + end + + assert_equal ["region", "code"], connection.primary_keys("barcodes") + + barcode = Barcode.first + assert_equal region, barcode.region + assert_equal code, barcode.code + ensure + Barcode.reset_column_information end def test_supports_extensions -- cgit v1.2.3