lib/findex/tasks.rb in findex-0.1.0 vs lib/findex/tasks.rb in findex-0.2.0
- old
+ new
@@ -3,40 +3,41 @@
require 'rake/tasklib'
namespace :db do
desc 'Finds indexes your application probably needs'
task :indexes => [:environment, :prepare] do
- indices = Findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
- Findex.send_indices(indices)
+ indices = @findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
+ @findex.send_indices(indices)
end
task :prepare do
- @generate_migration = ENV['migration'] == 'true'
- @perform_index = ENV['perform'] == 'true'
- @tables = ENV['tables'] ? ENV['tables'].split(',').map(&:strip) : nil
+ @findex = Findex.new
+ @findex.generate_migration = ENV['migration'] == 'true'
+ @findex.perform_index = ENV['perform'] == 'true'
+ @findex.tables = ENV['tables'] ? ENV['tables'].split(',').map(&:strip) : nil
Dir[File.join(Rails.root, 'app', 'models', '*.rb')].each do |file|
load(file)
end
end
namespace :indexes do
desc 'Finds unindexed boolean columns'
task :boolean => [:environment, :prepare] do
- @migration_name = 'boolean'
- Findex.send_indices(Findex.get_indices([:type, [:boolean]]))
+ @findex.migration_name = 'boolean'
+ @findex.send_indices(@findex.get_indices([:type, [:boolean]]))
end
desc 'Finds unindexed date, time, and datetime columns'
task :datetime => [:environment, :prepare] do
- @migration_name = 'datetime'
- Findex.send_indices(Findex.get_indices([:type, [:date, :datetime, :time]]))
+ @findex.migration_name = 'datetime'
+ @findex.send_indices(@findex.get_indices([:type, [:date, :datetime, :time]]))
end
desc 'Finds unindexed geo columns'
task :geo => [:environment, :prepare] do
- @migration_name = 'geo'
- Findex.send_indices(Findex.get_indices(:geo))
+ @findex.migration_name = 'geo'
+ @findex.send_indices(@findex.get_indices(:geo))
end
desc 'Prints instructions on how to use rake:db:indexes'
task :help do
puts ''
@@ -46,11 +47,11 @@
puts ''
puts " You can add migration=true to generate a migration file\n or perform=true to perform the indexing immediately:"
puts ' `rake db:indexes migration=true`'
puts ''
puts ' You can also target specific column types, like so:'
- for type in [:boolean, :datetime, :geo, :primary, :relationships]
+ [:boolean, :datetime, :geo, :primary, :relationships].each do |type|
puts " `rake db:indexes:#{type}`"
end
puts ''
puts ' You can also filter by column names and types, or by whole tables:'
puts ' `rake db:indexes:names names=type,state`'
@@ -59,54 +60,54 @@
puts ''
end
desc 'Generates a migration file with the recommended indexes'
task :migration => :environment do
- @generate_migration = true
- @perform_index = false
- indices = Findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
- Findex.send_indices(indices)
+ @findex.generate_migration = true
+ @findex.perform_index = false
+ indices = @findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
+ @findex.send_indices(indices)
end
desc 'Finds unindexed columns matching the names you supply'
task :names => [:environment, :prepare] do
if ENV['names']
- indices = Findex.get_indices([:name, ENV['names'].split(',').map(&:strip).map(&:intern)])
- Findex.send_indices(indices)
+ indices = @findex.get_indices([:name, ENV['names'].split(',').map(&:strip).map(&:intern)])
+ @findex.send_indices(indices)
else
puts ''
puts ' You must pass in a comma-separated collection of names like so'
puts ' `rake db:indexes:names names=type,state`'
puts ''
end
end
desc 'Performs a migration with the recommended indexes'
task :perform => :environment do
- @generate_migration = false
- @perform_index = true
- indices = Findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
- Findex.send_indices(indices)
+ @findex.generate_migration = false
+ @findex.perform_index = true
+ indices = @findex.get_indices(:geo, [:name, [:id, :type]], :primary, :reflection, [:type, [:boolean, :date, :datetime, :time]])
+ @findex.send_indices(indices)
end
desc 'Finds unindexed primary keys'
task :primary => [:environment, :prepare] do
- @migration_name = 'primary'
- Findex.send_indices(Findex.get_indices(:primary))
+ @findex.migration_name = 'primary'
+ @findex.send_indices(@findex.get_indices(:primary))
end
desc 'Finds unindexed relationship foreign keys'
task :relationships => [:environment, :prepare] do
- @migration_name = 'relationship'
- Findex.send_indices(Findex.get_indices(:reflection))
+ @findex.migration_name = 'relationship'
+ @findex.send_indices(@findex.get_indices(:reflection))
end
desc 'Finds unindexed columns matching the types you supply'
task :types => [:environment, :prepare] do
if ENV['types']
- indices = Findex.get_indices([:type, ENV['types'].split(',').map(&:strip).map(&:intern)])
- Findex.send_indices(indices)
+ indices = @findex.get_indices([:type, ENV['types'].split(',').map(&:strip).map(&:intern)])
+ @findex.send_indices(indices)
else
puts ''
puts ' You must pass in a comma-separated collection of types like so'
puts ' `rake db:indexes:types types=integer,decimal`'
puts ''
@@ -114,17 +115,17 @@
end
end
end
-module Findex
- def self.check_index(*args)
+class Findex
+ def check_index(*args)
index = args.shift
!args.any?{|array| array.any?{|comparison_index| comparison_index == index}}
end
- def self.collect_indices(indices)
+ def collect_indices(indices)
indices.collect{|table, columns| [table, columns.sort{|a, b|
if a == :id
-1
elsif b == :id
1
@@ -132,15 +133,15 @@
(a.is_a?(Array) ? a.map(&:to_s).join('_') : a.to_s) <=> (b.is_a?(Array) ? b.map(&:to_s).join('_') : b.to_s)
end
}]}.sort{|a, b| a[0].to_s <=> b[0].to_s}
end
- def self.connection
+ def connection
@connection ||= ActiveRecord::Base.connection
end
- def self.get_indices(*args)
+ def get_indices(*args)
indices = {}
ObjectSpace.each_object(Class) do |model|
next unless model.ancestors.include?(ActiveRecord::Base) && model != ActiveRecord::Base && model.table_exists?
next if @tables && !@tables.include?(model.table_name.to_s)
existing_indices = connection.indexes(model.table_name).map{|index| index.columns.length == 1 ? index.columns.first.to_sym : index.columns.map(&:to_sym) }
@@ -149,44 +150,44 @@
end
end
collect_indices(indices)
end
- def self.get_model_geo_indices(model, indices, existing_indices)
+ def get_model_geo_indices(model, indices, existing_indices)
indices[model.table_name] ||= []
parse_columns(model) do |column, column_name|
if column.type == :decimal && column.name =~ /(lat|lng)/ && model.column_names.include?(alternate_column_name = column.name.gsub(/(^|_)(lat|lng)($|_)/) { "#{$1}#{$2 == 'lat' ? 'lng' : 'lat'}#{$3}"})
index = [column_name, alternate_column_name.to_sym]
indices[model.table_name].push([column_name, alternate_column_name.to_sym]) if check_index(index, indices[model.table_name], existing_indices)
end
end
indices
end
- def self.get_model_name_indices(model, names, indices, existing_indices)
+ def get_model_name_indices(model, names, indices, existing_indices)
indices[model.table_name] ||= []
parse_columns(model) do |column, column_name|
if names.include?(column_name) && check_index(column_name, indices[model.table_name], existing_indices)
indices[model.table_name].push(column_name)
end
end
indices
end
- def self.get_model_primary_indices(model, indices, existing_indices)
+ def get_model_primary_indices(model, indices, existing_indices)
indices[model.table_name] ||= []
parse_columns(model) do |column, column_name|
if column.primary && check_index(column_name, indices[model.table_name], existing_indices)
indices[model.table_name].push(column_name)
end
end
indices
end
- def self.get_model_reflection_indices(model, indices, existing_indices)
+ def get_model_reflection_indices(model, indices, existing_indices)
indices[model.table_name] ||= []
- for name, reflection in model.reflections
+ model.reflections.each do |name, reflection|
case reflection.macro.to_sym
when :belongs_to
foreign_key = reflection.primary_key_name.to_sym
indices[model.table_name].push(foreign_key) if check_index(foreign_key, indices[model.table_name], existing_indices)
when :has_and_belongs_to_many
@@ -200,65 +201,85 @@
end
end
indices
end
- def self.get_model_type_indices(model, types, indices, existing_indices)
+ def get_model_type_indices(model, types, indices, existing_indices)
indices[model.table_name] ||= []
parse_columns(model) do |column, column_name|
if types.include?(column.type) && check_index(column_name, indices[model.table_name], existing_indices)
indices[model.table_name].push(column_name)
end
end
indices
end
- def self.parse_columns(model)
+ def parse_columns(model)
model.columns.each{|column| yield(column, column.name.to_sym)} if block_given?
end
- def self.send_indices(indices)
+ def send_indices(indices)
if @generate_migration
require 'rails_generator'
migration_path = File.join(RAILS_ROOT, 'db', 'migrate')
migration_number = 1
migration_test = "add#{"_#{@migration_name}" if @migration_name}_indexes"
- for file in Dir[File.join(migration_path, '*.rb')]
+ Dir[File.join(migration_path, '*.rb')].each do |file|
file = File.basename(file)
next unless file =~ /^\d+_#{migration_test}(\d+)\.rb$/
migration_number += 1
end
migration_name = "#{migration_test}#{migration_number}"
Rails::Generator::Base.instance('migration', [migration_name], {:command => :create, :generator => 'migration'}).command(:create).invoke!
if migration = Dir[File.join(migration_path, "*#{migration_name}.rb")].first
migration_up = []
migration_down = []
- for table, columns in indices.sort{|a, b| a[0].to_s <=> b[0].to_s}
+ indices.sort{|a, b| a[0].to_s <=> b[0].to_s}.each do |table, columns|
next if columns.empty?
- migration_up << "\s\s\s\s# Indices for `#{table}`"
- migration_down << "\s\s\s\s# Remove indices for `#{table}`"
- for column in columns
- migration_up << "\s\s\s\sadd_index :#{table}, #{column.inspect}"
- migration_down << "\s\s\s\sremove_index :#{table}, #{column.inspect}"
+ index_up = []
+ index_down = []
+ index_up.push("\s\s\s\s# Indices for `#{table}`")
+ index_down.push("\s\s\s\s# Remove indices for `#{table}`")
+ columns.each do |column|
+ index_up.push("\s\s\s\sadd_index :#{table}, #{column.inspect}")
+ index_down.push("\s\s\s\sremove_index :#{table}, #{column.inspect}")
end
+ migration_up.push(index_up.join("\n"))
+ migration_down.push(index_down.join("\n"))
end
- migration_contents = File.read(migration).gsub("def self.up", "def self.up\n#{migration_up.join("\n")}").gsub("def self.down", "def self.down\n#{migration_down.join("\n")}")
+ migration_contents = File.read(migration).gsub("def self.up", "def self.up\n#{migration_up.join("\n\n")}").gsub("def self.down", "def self.down\n#{migration_down.join("\n\n")}")
File.open(migration, 'w+') do |file|
file.puts migration_contents
- end
+ end
end
else
- for table, columns in indices.sort{|a, b| a[0].to_s <=> b[0].to_s}
+ indices.sort{|a, b| a[0].to_s <=> b[0].to_s}.each do |table, columns|
next if columns.empty?
puts "\s\s# Indices for `#{table}`"
- for column in columns
+ columns.each do |column|
if @perform_index
ActiveRecord::Migration.add_index(table, column)
else
puts "\s\sadd_index :#{table}, #{column.inspect}"
end
end
puts ''
end
end
+ end
+
+ def generate_migration=(value)
+ @generate_migration = !!value
+ end
+
+ def perform_index=(value)
+ @perform_index = !!value
+ end
+
+ def tables=(tables)
+ @tables = tables
+ end
+
+ def migration_name=(value)
+ @migration_name = value
end
end
\ No newline at end of file