Help with understanding railing db test

When I run a RSpec test for (JRuby + sqlite), but not (Ruby 1.9.3 + [mysql | postgres])

describe SomeModel do

  it { should have_db_index(:name).unique(true) }
end

The spec fails even though the schema.rb shows the db field as unquiely indexed.

ActiveRecord::Schema.define(:version => 20120908004000) do

create_table “some_model”, :force => true do |t|
t.string “name”, :limit => 63, :null => false
end
add_index “apps”, [“name”], :name => “index_apps_on_name”, :unique => true
end

The issue seems to be that MySQL and Postgres connection adapters behave differently than the Sqlite.

So I did some digging. The shoulda matchers use this to evaluate index uniqueness.

::ActiveRecord::Base.connection.indexes(App.table_name).detect {|e| e.columns == [“name”]}

sqlite

<struct ActiveRecord::ConnectionAdapters::IndexDefinition table=“apps”, name=“index_apps_on_name”, unique=7, columns=[“name”], lengths=nil, orders=nil>

mysql

<struct ActiveRecord::ConnectionAdapters::IndexDefinition table=“apps”, name=“index_apps_on_name”, unique=true, columns=[“name”], lengths=nil, orders=nil>

postgres

<struct ActiveRecord::ConnectionAdapters::IndexDefinition table=“apps”, name=“index_apps_on_name”, unique=true, columns=[“name”], lengths=nil, orders=nil>

The difference is mysql2: unqiue = true, pg: unique = true, sqlite: unique = 7.

(1)

Is Sqlite unique supposed to be 7?

I don’t think so.

(2)

If not, anyone know where would I go to refactor this?

Somewhere in ActiveRecord::ConnectionAdapters::SQLiteAdapter?

I tried looking in api.rubyonrails.org, but Postgres was the only adapter with the indexes method.

In Ruby,

$ irb
1.9.3-p194 :001 > if 7
1.9.3-p194 :002?> puts "hey"
1.9.3-p194 :003?> end
hey

Sounds like someone's got a bug. It should be just as true as the other ones.

Here is the location of indexes in the SQLiteAdapter:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L400

You can't assume the documentation always has everything in it.

awesome. thanks.

Oh, and in 3-2-stable, it's here:
https://github.com/rails/rails/blob/3-2-stable/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb#L361

But seriously, seems like Shoulda has a bug, not Rails.

Yeah, if I'm reading this right,
https://github.com/thoughtbot/shoulda-matchers/blob/master/lib/shoulda/matchers/active_record/have_db_index_matcher.rb#L65
is the offending line.

I'd make this code more like

is_unique = matched_index.unique

is_unique = not is_unique unless @options[:unique]

unless is_unique
  @missing = "#{table_name} has an index named #{matched_index.name} " <<
             "of unique #{matched_index.unique}, not #{@options[:unique]}."
end

Of course, I just did that in vim, no tests, so I might have screwed it up...

That would help.

It might also be a jruby issue.

ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin12.1.0]

#<Enumerator: [#<struct ActiveRecord::ConnectionAdapters::IndexDefinition table=“apps”, name=“index_apps_on_name”, unique=true, columns=[“name”], lengths=nil, orders=nil>]:detect>

jruby 1.6.7.2 (ruby-1.9.2-p312) (2012-05-01 26e08ba) (Java HotSpot™ 64-Bit Server VM 1.7.0_07) [darwin-x86_64-java]

#<Enumerator: [#<struct ActiveRecord::ConnectionAdapters::IndexDefinition table=“apps”, name=“index_apps_on_name”, unique=7, columns=[“name”], lengths=nil, orders=nil>]:detect>

I’ll test it on the rails-dev-box thingee tomorrow to make sure it’s not my env.

Let's see what team shoulda has to say:
https://github.com/thoughtbot/shoulda-matchers/pull/156