From a19e79859dd51147cfe1ca5c2f709c82eb6339b6 Mon Sep 17 00:00:00 2001 From: Aidan Feldman Date: Thu, 30 May 2013 04:10:32 -0400 Subject: [PATCH] add `mongoid:remove_undefined_indexes` rake task removes indexes that exist in the database but aren't specified on the models --- lib/mongoid/railties/database.rake | 6 ++++ lib/rails/mongoid.rb | 47 ++++++++++++++++++++++++++++ spec/rails/mongoid_spec.rb | 49 ++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/lib/mongoid/railties/database.rake b/lib/mongoid/railties/database.rake index cf69e23fa35..862cbf0793d 100644 --- a/lib/mongoid/railties/database.rake +++ b/lib/mongoid/railties/database.rake @@ -72,6 +72,12 @@ namespace :db do ::Rails::Mongoid.create_indexes end + desc "Remove indexes that exist in the database but aren't specified on the models" + task :remove_undefined_indexes => :environment do + ::Rails.application.eager_load! + ::Rails::Mongoid.remove_undefined_indexes + end + desc "Remove the indexes defined on your mongoid models without questions!" task :remove_indexes => :environment do ::Rails.application.eager_load! diff --git a/lib/rails/mongoid.rb b/lib/rails/mongoid.rb index 5b8909ec5b8..4b7e205059a 100644 --- a/lib/rails/mongoid.rb +++ b/lib/rails/mongoid.rb @@ -29,6 +29,53 @@ def create_indexes end.compact end + # Return the list of indexes by model that exist in the database but aren't + # specified on the models. + # + # @example Return the list of unused indexes. + # Rails::Mongoid.undefined_indexes + # + # @return Hash{Class => Array(Hash)} The list of undefined indexes by model. + def undefined_indexes + undefined_by_model = {} + + ::Mongoid.models.each do |model| + unless model.embedded? + model.collection.indexes.each do |index| + # ignore default index + unless index['name'] == '_id_' + key = index['key'].symbolize_keys + spec = model.index_specification(key) + unless spec + # index not specified + undefined_by_model[model] ||= [] + undefined_by_model[model] << index + end + end + end + end + end + + undefined_by_model + end + + # Remove indexes that exist in the database but aren't specified on the + # models. + # + # @example Remove undefined indexes. + # Rails::Mongoid.remove_undefined_indexes + # + # @return Hash{Class => Array(Hash)} The list of indexes that were removed by model. + def remove_undefined_indexes + undefined_indexes.each do |model, indexes| + indexes.each do |index| + key = index['key'].symbolize_keys + model.collection.indexes.drop(key) + logger.info("MONGOID: Removing index: #{index['name']} on #{model}.") + end + end + end + # Remove indexes for each model given the provided globs and the class is # not embedded. # diff --git a/spec/rails/mongoid_spec.rb b/spec/rails/mongoid_spec.rb index 57b9fe8e8b6..f186aaaf1ab 100644 --- a/spec/rails/mongoid_spec.rb +++ b/spec/rails/mongoid_spec.rb @@ -72,6 +72,55 @@ end end + describe ".undefined_indexes" do + + before(:each) do + Rails::Mongoid.create_indexes + end + + subject do + Rails::Mongoid.undefined_indexes + end + + it { should eq({}) } + + context "with extra index on model collection" do + before(:each) do + User.collection.indexes.create(account_expires: 1) + end + + its(:keys) { should eq([User]) } + + it "should have single index returned" do + names = subject[User].map{ |index| index['name'] } + expect(names).to eq(['account_expires_1']) + end + end + end + + describe ".remove_undefined_indexes" do + + let(:logger) do + stub + end + + let(:indexes) do + User.collection.indexes + end + + before(:each) do + Rails::Mongoid.create_indexes + indexes.create(account_expires: 1) + Rails::Mongoid.remove_undefined_indexes + end + + subject do + Rails::Mongoid.undefined_indexes + end + + it { should eq({}) } + end + describe ".remove_indexes" do let(:logger) do