Skip to content

Commit

Permalink
fix bugs re: uniqueness constraints, add specs
Browse files Browse the repository at this point in the history
  • Loading branch information
barunio committed Jan 30, 2012
1 parent cb57a5f commit ce67499
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 20 deletions.
50 changes: 32 additions & 18 deletions lib/polymorpheus/mysql_adapter.rb
Expand Up @@ -21,15 +21,21 @@ module MysqlAdapter
# `products` table # `products` table
# #
# options: a hash, corrently only accepts one option that allows us to # options: a hash, corrently only accepts one option that allows us to
# add an additional uniqueness constraint. so if the columns # add an additional uniqueness constraint.
# hash was specified as above, and we supplied options of # if the columns hash was specified as above, and we supplied
# { :unique => 'picture_url' } # options of
# { :unique => true }
# then this would create a uniqueness constraint in the database # then this would create a uniqueness constraint in the database
# that would ensure that no two employees could have the same # that would ensure that any given employee_id could only be in
# picture_url and no two products could have the same # the table once, and that any given product_id could only be in
# picture_url # the table once.
# (it would allow and employee and a product to have the same #
# picture_url) # alternatively, the user can also supply a column name or array
# of column names to the :unique option:
# { :unique => 'picture_url' }
# This would allow an employee_id (or product_id) to appear
# multiple times in the table, but no two employee ids would
# be able to have the same picture_url.


def add_polymorphic_constraints(table, columns, options={}) def add_polymorphic_constraints(table, columns, options={})
column_names = columns.keys.sort column_names = columns.keys.sort
Expand Down Expand Up @@ -116,22 +122,30 @@ def poly_create_triggers(table, columns)
end end


def poly_create_index(table, column, unique_cols) def poly_create_index(table, column, unique_cols)
unique_cols = unique_cols.collect(&:to_s) if unique_cols == [true]
name = poly_index_name(table, column, unique_cols) unique_cols = [column]
else
unique_cols = [column] + unique_cols
end
name = poly_index_name(table, unique_cols)
execute %{ execute %{
CREATE UNIQUE INDEX #{name} ON #{table} (#{column},#{unique_cols.join(',')}) CREATE UNIQUE INDEX #{name} ON #{table} (#{unique_cols.join(', ')})
} }
end end


def poly_remove_index(table, column, unique_cols) def poly_remove_index(table, column, unique_cols)
unique_cols = unique_cols.collect(&:to_s) if unique_cols == [true]
name = poly_index_name(table, column, unique_cols) unique_cols = [column]
else
unique_cols = [column] + unique_cols
end
name = poly_index_name(table, unique_cols)
execute %{ DROP INDEX #{name} ON #{table} } execute %{ DROP INDEX #{name} ON #{table} }
end end


def poly_index_name(table, column, unique_cols) def poly_index_name(table, columns)
prefix = "pfk_#{table}" prefix = "pfk_#{table}_"
generate_name prefix, [column] + unique_cols generate_name prefix, columns
end end


def poly_create_indexes(table, columns, unique_cols) def poly_create_indexes(table, columns, unique_cols)
Expand All @@ -148,10 +162,10 @@ def poly_remove_indexes(table, columns, unique_cols)


def generate_name(prefix, columns) def generate_name(prefix, columns)
# names can be at most 64 characters long # names can be at most 64 characters long
length_per_col = (64 - prefix.length) / columns.length col_length = (64 - prefix.length) / columns.length


prefix + prefix +
columns.map { |c| c.gsub('_','').first(length_per_col - 1) }.join('_') columns.map { |c| c.to_s.gsub('_','').first(col_length-1) }.join('_')
end end


end end
Expand Down
74 changes: 72 additions & 2 deletions spec/mysql2_adapter_spec.rb
Expand Up @@ -34,10 +34,10 @@ class << ActiveRecord::Base.connection


shared_examples_for "migration statements" do shared_examples_for "migration statements" do
describe "#add_polymorphic_constraints" do describe "#add_polymorphic_constraints" do
before { connection.add_polymorphic_constraints(table, columns) } before { connection.add_polymorphic_constraints(table, columns, options) }


specify do specify do
clean_sql(sql.join("\n")).should == clean_sql(trigger_sql + fkey_sql) clean_sql(sql.join("\n")).should == clean_sql(full_constraints_sql)
end end
end end


Expand All @@ -53,6 +53,7 @@ class << ActiveRecord::Base.connection
context "when the table and column names are not too long" do context "when the table and column names are not too long" do
let(:table) { 'pets' } let(:table) { 'pets' }
let(:columns) { { 'kitty_id' => 'cats.name', 'dog_id' => 'dogs.id' } } let(:columns) { { 'kitty_id' => 'cats.name', 'dog_id' => 'dogs.id' } }
let(:options) { {} }


let(:trigger_sql) do let(:trigger_sql) do
%{ %{
Expand Down Expand Up @@ -82,7 +83,67 @@ class << ActiveRecord::Base.connection
} }
end end


let(:full_constraints_sql) { trigger_sql + fkey_sql }

it_behaves_like "migration statements" it_behaves_like "migration statements"

context "and we specify a uniqueness constraint as true" do
let(:options) { { :unique => true } }
let(:unique_key_sql) do
%{
CREATE UNIQUE INDEX pfk_pets_dogid ON pets (dog_id)
CREATE UNIQUE INDEX pfk_pets_kittyid ON pets (kitty_id)
}
end

let(:full_constraints_sql) { trigger_sql + unique_key_sql + fkey_sql }

it_behaves_like "migration statements"
end

context "and we specify a uniqueness constraint as a string" do
let(:options) { { :unique => 'field1' } }
let(:unique_key_sql) do
%{
CREATE UNIQUE INDEX pfk_pets_dogid_field1 ON pets (dog_id, field1)
CREATE UNIQUE INDEX pfk_pets_kittyid_field1 ON pets (kitty_id, field1)
}
end

let(:full_constraints_sql) { trigger_sql + unique_key_sql + fkey_sql }

it_behaves_like "migration statements"
end

context "and we specify a uniqueness constraint as an array" do
let(:options) { { :unique => [:foo, :bar] } }
let(:unique_key_sql) do
%{
CREATE UNIQUE INDEX pfk_pets_dogid_foo_bar ON pets (dog_id, foo, bar)
CREATE UNIQUE INDEX pfk_pets_kittyid_foo_bar ON pets (kitty_id, foo, bar)
}
end

let(:full_constraints_sql) { trigger_sql + unique_key_sql + fkey_sql }

it_behaves_like "migration statements"
end

context "and we specify a uniqueness constraint on fields with really long names" do
let(:options) do
{ :unique => [:fee_was_a_buddhist_prodigy, :ground_control_to_major_tom] }
end
let(:unique_key_sql) do
%{
CREATE UNIQUE INDEX pfk_pets_dogid_feewasabuddhistpr_groundcontroltoma ON pets (dog_id, fee_was_a_buddhist_prodigy, ground_control_to_major_tom)
CREATE UNIQUE INDEX pfk_pets_kittyid_feewasabuddhistpr_groundcontroltoma ON pets (kitty_id, fee_was_a_buddhist_prodigy, ground_control_to_major_tom)
}
end

let(:full_constraints_sql) { trigger_sql + unique_key_sql + fkey_sql }

it_behaves_like "migration statements"
end
end end


context "when the table and column names combined are very long" do context "when the table and column names combined are very long" do
Expand All @@ -91,6 +152,7 @@ class << ActiveRecord::Base.connection
{ 'im_too_cool_to_vote_and_ill_only_ride_a_fixie' => 'hipster.id', { 'im_too_cool_to_vote_and_ill_only_ride_a_fixie' => 'hipster.id',
'really_im_not_doping_i_just_practice_a_lot' => 'professional.id' } 'really_im_not_doping_i_just_practice_a_lot' => 'professional.id' }
end end
let(:options) { {} }


let(:trigger_sql) do let(:trigger_sql) do
%{ %{
Expand Down Expand Up @@ -120,6 +182,14 @@ class << ActiveRecord::Base.connection
} }
end end


let(:unique_key_sql) do
%{
CREATE UNIQUE INDEX pfk_blah
}
end

let(:full_constraints_sql) { trigger_sql + fkey_sql }

it_behaves_like "migration statements" it_behaves_like "migration statements"
end end


Expand Down

0 comments on commit ce67499

Please sign in to comment.