rails-indexes 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rails-indexes.gemspec
4
+ gemspec
@@ -0,0 +1,37 @@
1
+ h1. Rails Indexes
2
+
3
+ Rails indexes is a small package of 2 rake tasks that scan your application models and displays a list of columns that _probably_ should be indexed.
4
+
5
+ note: there should be mode fields depending on your application design and custom queries.
6
+
7
+ h2. Installation
8
+
9
+ as a rails plugin:
10
+ <pre>script/plugin install git://github.com/eladmeidar/rails_indexes.git</pre>
11
+
12
+ h2. Usage
13
+
14
+ Display a migration for adding/removing all necessary indexes based on associations:
15
+ <pre>rake db:index_migration</pre>
16
+
17
+ Display a migration for adding/removing all necessary indexes based on AR::Base#find calls (including: find, find_by, find_all_by, find_by_x_and_y, find_all_by_x_and_y):
18
+ <pre>rake db:find_query_indexes</pre>
19
+
20
+ Note that it would probably make more sense running those tasks on production, where you *actually* need those indexes to be added.
21
+
22
+ h2. Tests
23
+
24
+ Requires SQLite3 installed, then just:
25
+ <pre>rake</pre>
26
+ to run the tests
27
+
28
+ h4. Author:
29
+
30
+ Elad Meidar - "http://blog.eizesus.com":http://blog.eizesus.com
31
+
32
+ Thanks:
33
+ Eric Davis - "http://littlestreamsoftware.com":http://littlestreamsoftware.com
34
+
35
+ Released under the same license as Ruby. No Support. No Warranty, no Pain.
36
+
37
+
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,7 @@
1
+ require "rails-indexes/version"
2
+ require "rails-indexes/indexer"
3
+
4
+ module TechnoGate
5
+ module RailsIndexes
6
+ end
7
+ end
@@ -0,0 +1,335 @@
1
+ module TechnoGate
2
+ module RailsIndexes
3
+ module Indexer
4
+
5
+ def self.sortalize(array)
6
+ Marshal.load(Marshal.dump(array)).each do |element|
7
+ element.sort! if element.is_a?(Array)
8
+ end
9
+ end
10
+
11
+ def self.check_for_indexes(migration_format = false)
12
+ model_names = []
13
+ Dir.chdir(Rails.root) do
14
+ model_names = Dir["**/app/models/**/*.rb"].collect {|filename| File.basename(filename) }.uniq
15
+ end
16
+
17
+ model_classes = []
18
+ model_names.each do |model_name|
19
+ class_name = model_name.sub(/\.rb$/,'').camelize
20
+ begin
21
+ klass = class_name.split('::').inject(Object){ |klass,part| klass.const_get(part) }
22
+ if klass < ActiveRecord::Base && !klass.abstract_class?
23
+ model_classes << klass
24
+ end
25
+ rescue
26
+ # No-op
27
+ end
28
+ end
29
+
30
+ @index_migrations = Hash.new([])
31
+
32
+ model_classes.each do |class_name|
33
+
34
+ # check if this is an STI child instance
35
+ if class_name.base_class.name != class_name.name && (class_name.column_names.include?(class_name.base_class.inheritance_column) || class_name.column_names.include?(class_name.inheritance_column))
36
+
37
+ # add the inharitance column on the parent table
38
+ # index migration for STI should require both the primary key and the inheritance_column in a composite index.
39
+ @index_migrations[class_name.base_class.table_name] += [[class_name.inheritance_column, class_name.base_class.primary_key].sort] unless @index_migrations[class_name.base_class.table_name].include?([class_name.base_class.inheritance_column].sort)
40
+ end
41
+ #puts "class name: #{class_name}"
42
+ class_name.reflections.each_pair do |reflection_name, reflection_options|
43
+ #puts "reflection => #{reflection_name}"
44
+ case reflection_options.macro
45
+ when :belongs_to
46
+ # polymorphic?
47
+ @table_name = class_name.table_name.to_s
48
+ if reflection_options.options.has_key?(:polymorphic) && (reflection_options.options[:polymorphic] == true)
49
+ poly_type = "#{reflection_options.name.to_s}_type"
50
+ poly_id = "#{reflection_options.name.to_s}_id"
51
+
52
+ @index_migrations[@table_name.to_s] += [[poly_type, poly_id].sort] unless @index_migrations[@table_name.to_s].include?([poly_type, poly_id].sort)
53
+ else
54
+
55
+ foreign_key = reflection_options.options[:foreign_key] ||= reflection_options.primary_key_name
56
+ @index_migrations[@table_name.to_s] += [foreign_key] unless @index_migrations[@table_name.to_s].include?(foreign_key)
57
+ end
58
+ when :has_and_belongs_to_many
59
+ table_name = reflection_options.options[:join_table] ||= [class_name.table_name, reflection_name.to_s].sort.join('_')
60
+ association_foreign_key = reflection_options.options[:association_foreign_key] ||= "#{reflection_name.to_s.singularize}_id"
61
+
62
+ # Guess foreign key?
63
+ if reflection_options.options[:foreign_key]
64
+ foreign_key = reflection_options.options[:foreign_key]
65
+ elsif reflection_options.options[:class_name]
66
+ foreign_key = reflection_options.options[:class_name].foreign_key
67
+ else
68
+ foreign_key = "#{class_name.name.tableize.singularize}_id"
69
+ end
70
+
71
+ composite_keys = [association_foreign_key, foreign_key]
72
+
73
+ @index_migrations[table_name.to_s] += [composite_keys] unless @index_migrations[table_name].include?(composite_keys)
74
+ @index_migrations[table_name.to_s] += [composite_keys.reverse] unless @index_migrations[table_name].include?(composite_keys.reverse)
75
+
76
+ else
77
+ #nothing
78
+ end
79
+ end
80
+ end
81
+
82
+ @missing_indexes = {}
83
+
84
+ @index_migrations.each do |table_name, foreign_keys|
85
+
86
+ unless foreign_keys.blank?
87
+ existing_indexes = ActiveRecord::Base.connection.indexes(table_name.to_sym).collect {|index| index.columns.size > 1 ? index.columns : index.columns.first}
88
+ keys_to_add = foreign_keys.uniq - existing_indexes #self.sortalize(foreign_keys.uniq) - self.sortalize(existing_indexes)
89
+ @missing_indexes[table_name] = keys_to_add unless keys_to_add.empty?
90
+ end
91
+ end
92
+
93
+ @missing_indexes
94
+ end
95
+
96
+ def self.scan_finds
97
+
98
+
99
+ # Collect all files that can contain queries, in app/ directories (includes plugins and such)
100
+ # TODO: add lib too ?
101
+ file_names = []
102
+
103
+ Dir.chdir(Rails.root) do
104
+ file_names = Dir["**/app/**/*.rb"].uniq.reject {|file_with_path| file_with_path.include?('test')}
105
+ end
106
+
107
+ @indexes_required = Hash.new([])
108
+
109
+ # Scan each file
110
+ file_names.each do |file_name|
111
+ current_file = File.open(File.join(Rails.root, file_name), 'r')
112
+
113
+ # Scan each line
114
+ current_file.each do |line|
115
+
116
+ # by default, try to add index on primary key, based on file name
117
+ # this will fail if the file isnot a model file
118
+
119
+ begin
120
+ current_model_name = File.basename(file_name).sub(/\.rb$/,'').camelize
121
+ rescue
122
+ # NO-OP
123
+ end
124
+
125
+ # Get the model class
126
+ klass = current_model_name.split('::').inject(Object){ |klass,part| klass.const_get(part) } rescue nil
127
+
128
+ # Only add primary key for active record dependent classes and non abstract ones too.
129
+ if klass.present? && klass < ActiveRecord::Base && !klass.abstract_class?
130
+ current_model = current_model_name.constantize
131
+ primary_key = current_model.primary_key
132
+ table_name = current_model.table_name
133
+ @indexes_required[table_name] += [primary_key] unless @indexes_required[table_name].include?(primary_key)
134
+ end
135
+
136
+ check_line_for_find_indexes(file_name, line)
137
+
138
+ end
139
+ end
140
+
141
+ @missing_indexes = {}
142
+ @indexes_required.each do |table_name, foreign_keys|
143
+
144
+ unless foreign_keys.blank?
145
+ begin
146
+ if ActiveRecord::Base.connection.tables.include?(table_name.to_s)
147
+ existing_indexes = ActiveRecord::Base.connection.indexes(table_name.to_sym).collect {|index| index.columns.size > 1 ? index.columns : index.columns.first}
148
+ keys_to_add = self.sortalize(foreign_keys.uniq) - self.sortalize(existing_indexes)
149
+ @missing_indexes[table_name] = keys_to_add unless keys_to_add.empty?
150
+ else
151
+ puts "BUG: table '#{table_name.to_s}' does not exist, please report this bug."
152
+ end
153
+ rescue Exception => e
154
+ puts "ERROR: #{e}"
155
+ end
156
+ end
157
+ end
158
+
159
+ @indexes_required
160
+ end
161
+
162
+ # Check line for find* methods (include find_all, find_by and just find)
163
+ def self.check_line_for_find_indexes(file_name, line)
164
+
165
+ # TODO: Assumes that you have a called on #find. you can actually call #find without a caller in a model code. ex:
166
+ # def something
167
+ # find(self.id)
168
+ # end
169
+ #
170
+ # find_regexp = Regexp.new(/([A-Z]{1}[A-Za-z]+|self).(find){1}((_all){0,1}(_by_){0,1}([A-Za-z_]+))?\(([0-9A-Za-z"\':=>. \[\]{},]*)\)/)
171
+
172
+ find_regexp = Regexp.new(/(([A-Z]{1}[A-Za-z]+|self).)?(find){1}((_all){0,1}(_by_){0,1}([A-Za-z_]+))?\(([0-9A-Za-z"\':=>. \[\]{},]*)\)/)
173
+
174
+ # If line matched a finder
175
+ if matches = find_regexp.match(line)
176
+
177
+ model_name, column_names, options = matches[2], matches[7], matches[8]
178
+
179
+ # if the finder class is "self" or empty (can be a simple "find()" in a model)
180
+ if model_name == "self" || model_name.blank?
181
+ model_name = File.basename(file_name).sub(/\.rb$/,'').camelize
182
+ table_name = model_name.constantize.table_name
183
+ else
184
+ if model_name.respond_to?(:constantize)
185
+ if model_name.constantize.respond_to?(:table_name)
186
+ table_name = model_name.constantize.table_name
187
+ end
188
+ end
189
+ end
190
+
191
+ # Check that all prerequisites are met
192
+ if model_name.present? && table_name.present? && model_name.constantize.ancestors.include?(ActiveRecord::Base)
193
+ primary_key = model_name.constantize.primary_key
194
+ @indexes_required[table_name] += [primary_key] unless @indexes_required[table_name].include?(primary_key)
195
+
196
+ if column_names.present?
197
+ column_names = column_names.split('_and_')
198
+
199
+ # remove find_by_sql references.
200
+ column_names.delete("sql")
201
+
202
+ column_names = model_name.constantize.column_names & column_names
203
+
204
+ # Check if there were more than 1 column
205
+ if column_names.size == 1
206
+ column_name = column_names.first
207
+ @indexes_required[table_name] += [column_name] unless @indexes_required[table_name].include?(column_name)
208
+ else
209
+ @indexes_required[table_name] += [column_names] unless @indexes_required[table_name].include?(column_names)
210
+ @indexes_required[table_name] += [column_names.reverse] unless @indexes_required[table_name].include?(column_names.reverse)
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
216
+
217
+ def self.key_exists?(table,key_columns)
218
+ result = (key_columns.to_a - ActiveRecord::Base.connection.indexes(table).map { |i| i.columns }.flatten)
219
+ result.empty?
220
+ end
221
+
222
+ def self.simple_migration
223
+ migration_format = true
224
+ missing_indexes = check_for_indexes(migration_format)
225
+
226
+ unless missing_indexes.keys.empty?
227
+ add = []
228
+ remove = []
229
+ missing_indexes.each do |table_name, keys_to_add|
230
+ keys_to_add.each do |key|
231
+ next if key_exists?(table_name,key)
232
+ next if key.blank?
233
+ if key.is_a?(Array)
234
+ keys = key.collect {|k| ":#{k}"}
235
+ add << "add_index :#{table_name}, [#{keys.join(', ')}]"
236
+ remove << "remove_index :#{table_name}, :column => [#{keys.join(', ')}]"
237
+ else
238
+ add << "add_index :#{table_name}, :#{key}"
239
+ remove << "remove_index :#{table_name}, :#{key}"
240
+ end
241
+
242
+ end
243
+ end
244
+
245
+ migration = <<-EOM
246
+ class AddMissingIndexes < ActiveRecord::Migration
247
+ def self.up
248
+
249
+ # These indexes were found by searching for AR::Base finds on your application
250
+ # It is strongly recommanded that you will consult a professional DBA about your infrastucture and implemntation before
251
+ # changing your database in that matter.
252
+ # There is a possibility that some of the indexes offered below is not required and can be removed and not added, if you require
253
+ # further assistance with your rails application, database infrastructure or any other problem, visit:
254
+ #
255
+ # http://www.railsmentors.org
256
+ # http://www.railstutor.org
257
+ # http://guides.rubyonrails.org
258
+
259
+
260
+ #{add.uniq.join("\n ")}
261
+ end
262
+
263
+ def self.down
264
+ #{remove.uniq.join("\n ")}
265
+ end
266
+ end
267
+ EOM
268
+
269
+ puts "## Drop this into a file in db/migrate ##"
270
+ puts migration
271
+ end
272
+ end
273
+
274
+ def self.indexes_list
275
+ check_for_indexes.each do |table_name, keys_to_add|
276
+ puts "Table '#{table_name}' => #{keys_to_add.to_sentence}"
277
+ end
278
+ end
279
+
280
+ def self.ar_find_indexes(migration_mode=true)
281
+ find_indexes = self.scan_finds
282
+
283
+ if migration_mode
284
+ unless find_indexes.keys.empty?
285
+ add = []
286
+ remove = []
287
+ find_indexes.each do |table_name, keys_to_add|
288
+ keys_to_add.each do |key|
289
+ next if key_exists?(table_name,[key].flatten)
290
+ next if key.blank?
291
+ if key.is_a?(Array)
292
+ keys = key.collect {|k| ":#{k}"}
293
+ add << "add_index :#{table_name}, [#{keys.join(', ')}]"
294
+ remove << "remove_index :#{table_name}, :column => [#{keys.join(', ')}]"
295
+ else
296
+ add << "add_index :#{table_name}, :#{key}"
297
+ remove << "remove_index :#{table_name}, :#{key}"
298
+ end
299
+
300
+ end
301
+ end
302
+
303
+ migration = <<-EOM
304
+ class AddFindsMissingIndexes < ActiveRecord::Migration
305
+ def self.up
306
+
307
+ # These indexes were found by searching for AR::Base finds on your application
308
+ # It is strongly recommanded that you will consult a professional DBA about your infrastucture and implemntation before
309
+ # changing your database in that matter.
310
+ # There is a possibility that some of the indexes offered below is not required and can be removed and not added, if you require
311
+ # further assistance with your rails application, database infrastructure or any other problem, visit:
312
+ #
313
+ # http://www.railsmentors.org
314
+ # http://www.railstutor.org
315
+ # http://guides.rubyonrails.org
316
+
317
+ #{add.uniq.join("\n ")}
318
+ end
319
+
320
+ def self.down
321
+ #{remove.uniq.join("\n ")}
322
+ end
323
+ end
324
+ EOM
325
+
326
+ puts "## Drop this into a file in db/migrate ##"
327
+ puts migration
328
+ end
329
+ end
330
+ else
331
+ find_indexes
332
+ end
333
+ end
334
+ end
335
+ end
@@ -0,0 +1,5 @@
1
+ module TechnoGate
2
+ module RailsIndexes
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ require 'rails-indexes'
2
+
3
+ namespace :db do
4
+ desc "collect indexes based on AR::Base.find calls."
5
+ task :find_query_indexes => :environment do
6
+ TechnoGate::RailsIndexes::Indexer.ar_find_indexes
7
+ end
8
+
9
+ task :index_migration => :environment do
10
+ TechnoGate::RailsIndexes::Indexer.simple_migration
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rails-indexes/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rails-indexes"
7
+ s.version = TechnoGate::RailsIndexes::VERSION
8
+ s.authors = ["Elad Meidar", "Wael Nasreddine"]
9
+ s.email = ["elad@eizesus.com","wael.nasreddine@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A rake task to track down missing database indexes. does not assume that all foreign keys end with the convention of _id.}
12
+ s.description = %q{A rake task to track down missing database indexes. does not assume that all foreign keys end with the convention of _id.}
13
+
14
+ s.rubyforge_project = "rails-indexes"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
@@ -0,0 +1,14 @@
1
+ class CatsController < ActionController::Base
2
+
3
+ before_filter :find_commentable
4
+
5
+ def index
6
+ @cats = nil
7
+ end
8
+
9
+ protected
10
+
11
+ def find_commentable
12
+ #do something awesome
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ class UsersController < ActionController::Base
2
+
3
+
4
+ def index
5
+ @freelancer = Freelancer.find_all_by_name(param[:name])
6
+ @user = User.find(1)
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class Address < ActiveRecord::Base
2
+
3
+ belongs_to :addressable, :polymorphic => true
4
+ belongs_to :country
5
+ end
@@ -0,0 +1,11 @@
1
+ class Company < ActiveRecord::Base
2
+
3
+ belongs_to :owner, :foreign_key => 'owner_id', :class_name => 'User'
4
+ belongs_to :country
5
+
6
+ has_one :address, :as => :addressable
7
+
8
+ has_many :users
9
+
10
+ has_and_belongs_to_many :freelancers
11
+ end
@@ -0,0 +1,4 @@
1
+ class Country < ActiveRecord::Base
2
+ has_many :addresses
3
+ has_many :companies
4
+ end
@@ -0,0 +1,3 @@
1
+ class Freelancer < ActiveRecord::Base
2
+ has_and_belongs_to_many :companies
3
+ end
@@ -0,0 +1,10 @@
1
+ class Gift < ActiveRecord::Base
2
+
3
+ set_primary_key :custom_primary_key
4
+ has_and_belongs_to_many :users, :join_table => "purchases", :association_foreign_key => 'buyer_id', :foreign_key => 'present_id'
5
+
6
+ def search_all(name, price)
7
+ Gift.find_all_by_name_and_price(name, price)
8
+ end
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ class God < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -0,0 +1,17 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ has_one :company, :foreign_key => 'owner_id'
4
+ has_one :address, :as => :addressable
5
+
6
+ has_and_belongs_to_many :users, :join_table => "purchases", :association_foreign_key => 'present_id', :foreign_key => 'buyer_id'
7
+
8
+ validates_uniqueness_of :name
9
+
10
+ def search_via_email(email = "user@domain.com")
11
+ self.find_by_email(email)
12
+ end
13
+
14
+ def search_via_email_and_name(email, name)
15
+ self.find_by_email_and_name(email, name)
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ class UserSweeper < ActionController::Caching::Sweeper
2
+ # This sweeper is going to keep an eye on the Product model
3
+ observe User
4
+
5
+ # If our sweeper detects that a Product was created call this
6
+ def after_create(product)
7
+ logger.info "Sweeped!"
8
+ end
9
+ end
@@ -0,0 +1,46 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table "users", :force => true do |t|
3
+ t.column "name", :text
4
+ t.column "email", :text
5
+ end
6
+
7
+ create_table "companies", :force => true do |t|
8
+ t.column "name", :text
9
+ t.column "owned_id", :integer
10
+ t.column "country_id", :integer
11
+ end
12
+
13
+ add_index :companies, :country_id
14
+
15
+ create_table "addresses", :force => true do |t|
16
+ t.column "addressable_type", :string
17
+ t.column "addressable_id", :integer
18
+ t.column "address", :text
19
+ t.column "country_id", :integer
20
+ end
21
+
22
+ create_table "freelancers", :force => true do |t|
23
+ t.column "name", :string
24
+ t.column "price_per_hour", :integer
25
+ end
26
+
27
+ create_table "companies_freelancers", :force => true do |t|
28
+ t.column "freelancer_id", :integer
29
+ t.column "company_id", :integer
30
+ end
31
+
32
+ create_table "gifts", :force => true do |t|
33
+ t.column "custom_primary_key", :integer
34
+ t.column "name", :string
35
+ t.column "price", :integer
36
+ end
37
+
38
+ create_table "purchases", :force => true do |t|
39
+ t.column "present_id", :integer
40
+ t.column "buyer_id", :integer
41
+ end
42
+
43
+ create_table "countries", :force => true do |t|
44
+ t.column "name", :string
45
+ end
46
+ end
@@ -0,0 +1,83 @@
1
+ require 'test_helper'
2
+
3
+ class RailsIndexesTest < ActiveSupport::TestCase
4
+
5
+ test "relationship indexes are found" do
6
+ @relationship_indexes = Indexer.check_for_indexes
7
+
8
+ assert @relationship_indexes.size > 0
9
+
10
+ assert @relationship_indexes.has_key?("companies")
11
+ assert @relationship_indexes.has_key?("companies_freelancers")
12
+ assert @relationship_indexes.has_key?("addresses")
13
+ assert @relationship_indexes.has_key?("purchases")
14
+ end
15
+
16
+ # should add 2 composite indexes or each pair
17
+ test "has_and_belongs_to_many" do
18
+ @relationship_indexes = Indexer.check_for_indexes(true)
19
+
20
+ assert @relationship_indexes["companies_freelancers"].include?(["company_id", "freelancer_id"])
21
+ assert @relationship_indexes["companies_freelancers"].include?(["freelancer_id", "company_id"])
22
+ end
23
+
24
+ test "has_and_belongs_to_many with custom columns" do
25
+ @relationship_indexes = Indexer.check_for_indexes(true)
26
+
27
+ assert @relationship_indexes["purchases"].include?(["present_id", "buyer_id"])
28
+ assert @relationship_indexes["purchases"].include?(["buyer_id", "present_id"])
29
+ end
30
+
31
+ test "belongs_to" do
32
+ @relationship_indexes = Indexer.check_for_indexes(true)
33
+ assert @relationship_indexes["addresses"].include?("country_id")
34
+ end
35
+
36
+ test "belongs_to with a custom foreign key" do
37
+ @relationship_indexes = Indexer.check_for_indexes(true)
38
+ assert @relationship_indexes["companies"].include?("owner_id")
39
+ end
40
+
41
+ test "should not add an already existing index" do
42
+ @relationship_indexes = Indexer.check_for_indexes(true)
43
+ assert !(@relationship_indexes["companies"].include?("country_id"))
44
+ end
45
+
46
+ test "default find_by indexes for primary keys" do
47
+ @find_by_indexes = Indexer.ar_find_indexes(false)
48
+
49
+ # Default added the primary key for each table
50
+ assert @find_by_indexes.has_key?("users")
51
+ assert @find_by_indexes.has_key?("companies")
52
+ assert @find_by_indexes.has_key?("gifts")
53
+ assert @find_by_indexes.has_key?("freelancers")
54
+ assert @find_by_indexes.has_key?("countries")
55
+ end
56
+
57
+ test "default find_by indexes for custom primary keys" do
58
+ @find_by_indexes = Indexer.ar_find_indexes(false)
59
+
60
+ assert @find_by_indexes["gifts"].include?("custom_primary_key")
61
+ end
62
+
63
+ test "find_by indexes for self.find_by_email_and_name" do
64
+ @find_by_indexes = Indexer.ar_find_indexes(false)
65
+
66
+ assert @find_by_indexes["users"].include?(["name", "email"])
67
+ assert @find_by_indexes["users"].include?(["email", "name"])
68
+ end
69
+
70
+ test "find_by indexes for Gift.find_all_by_name_and_price" do
71
+ @find_by_indexes = Indexer.ar_find_indexes(false)
72
+
73
+ assert @find_by_indexes["gifts"].include?(["name", "price"])
74
+ assert @find_by_indexes["gifts"].include?(["price", "name"])
75
+ end
76
+
77
+ test "find_by indexes from UsersController" do
78
+ @find_by_indexes = Indexer.ar_find_indexes(false)
79
+
80
+ assert @find_by_indexes["freelancers"].include?("name")
81
+
82
+ end
83
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+
3
+ require 'test/unit'
4
+
5
+ require 'active_record'
6
+ require 'active_record/fixtures'
7
+ require 'active_support'
8
+ require 'active_support/test_case'
9
+ require 'action_controller'
10
+
11
+ require 'indexer'
12
+
13
+ ActiveRecord::Base.establish_connection(
14
+ :adapter => "sqlite3",
15
+ :database => ":memory:"
16
+ )
17
+
18
+ class Rails
19
+ def self.root
20
+ "test/fixtures/"
21
+ end
22
+ end
23
+
24
+ load 'test/fixtures/schema.rb'
25
+
26
+ # Load models
27
+ Dir['test/fixtures/app/models/**/*.rb'].each { |f| require f }
28
+
29
+ # load controllers
30
+ Dir['test/fixtures/app/controllers/**/*.rb'].each { |f| require f }
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-indexes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Elad Meidar
9
+ - Wael Nasreddine
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-07-03 00:00:00.000000000 +02:00
14
+ default_executable:
15
+ dependencies: []
16
+ description: A rake task to track down missing database indexes. does not assume that
17
+ all foreign keys end with the convention of _id.
18
+ email:
19
+ - elad@eizesus.com
20
+ - wael.nasreddine@gmail.com
21
+ executables: []
22
+ extensions: []
23
+ extra_rdoc_files: []
24
+ files:
25
+ - .gitignore
26
+ - Gemfile
27
+ - README.textile
28
+ - Rakefile
29
+ - lib/rails-indexes.rb
30
+ - lib/rails-indexes/indexer.rb
31
+ - lib/rails-indexes/version.rb
32
+ - lib/tasks/indexer.rake
33
+ - rails-indexes.gemspec
34
+ - test/fixtures/app/controllers/cats_controller.rb
35
+ - test/fixtures/app/controllers/users_controller.rb
36
+ - test/fixtures/app/models/address.rb
37
+ - test/fixtures/app/models/company.rb
38
+ - test/fixtures/app/models/country.rb
39
+ - test/fixtures/app/models/freelancer.rb
40
+ - test/fixtures/app/models/gift.rb
41
+ - test/fixtures/app/models/god.rb
42
+ - test/fixtures/app/models/user.rb
43
+ - test/fixtures/app/sweepers/user_sweeper.rb
44
+ - test/fixtures/schema.rb
45
+ - test/rails_indexes_test.rb
46
+ - test/test_helper.rb
47
+ has_rdoc: true
48
+ homepage: ''
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project: rails-indexes
68
+ rubygems_version: 1.6.2
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: A rake task to track down missing database indexes. does not assume that
72
+ all foreign keys end with the convention of _id.
73
+ test_files:
74
+ - test/fixtures/app/controllers/cats_controller.rb
75
+ - test/fixtures/app/controllers/users_controller.rb
76
+ - test/fixtures/app/models/address.rb
77
+ - test/fixtures/app/models/company.rb
78
+ - test/fixtures/app/models/country.rb
79
+ - test/fixtures/app/models/freelancer.rb
80
+ - test/fixtures/app/models/gift.rb
81
+ - test/fixtures/app/models/god.rb
82
+ - test/fixtures/app/models/user.rb
83
+ - test/fixtures/app/sweepers/user_sweeper.rb
84
+ - test/fixtures/schema.rb
85
+ - test/rails_indexes_test.rb
86
+ - test/test_helper.rb