full_table_scan_matchers 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +27 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +88 -0
- data/Rakefile +31 -0
- data/bin/setup +8 -0
- data/config/database.travis.yml +5 -0
- data/full_table_scan_matchers.gemspec +28 -0
- data/lib/full_table_scan_matchers.rb +39 -0
- data/lib/full_table_scan_matchers/configuration.rb +14 -0
- data/lib/full_table_scan_matchers/db_adapters.rb +4 -0
- data/lib/full_table_scan_matchers/db_adapters/mysql.rb +6 -0
- data/lib/full_table_scan_matchers/db_adapters/mysql/explain_result.rb +61 -0
- data/lib/full_table_scan_matchers/matchers/full_table_scan.rb +79 -0
- data/lib/full_table_scan_matchers/sql_watcher.rb +63 -0
- data/lib/full_table_scan_matchers/version.rb +3 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 461eb2bcbdf13c351343b98640ee0e110fcd2ff6
|
4
|
+
data.tar.gz: 0fc519dd6462d5befb9cbe595882d50c4850cebc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e7379fddc8b2b57e61fa4200ae2a005d7be85f8836dfba1f4c75f8bb3612da8a8d635e7ce7710d6b444a649806356ffd82a66e1dff7697beba4a1a2dc77daecd
|
7
|
+
data.tar.gz: 14f459f90f4ed869c77d3620f30aa22e0d80cc9a088feebaeb6e1364eb5881d5434764da724953cf8665a965ae3fa8a35cbbd5abb6263e3c56d1765528c419f9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
services:
|
2
|
+
- mysql
|
3
|
+
sudo: false
|
4
|
+
cache: bundler
|
5
|
+
language: ruby
|
6
|
+
rvm:
|
7
|
+
- 2.0.0
|
8
|
+
- 2.1.0
|
9
|
+
- 2.2.0
|
10
|
+
- 2.3.0
|
11
|
+
- 2.3.1
|
12
|
+
env:
|
13
|
+
- RAILS_VERSION=4
|
14
|
+
- RAILS_VERSION=5
|
15
|
+
matrix:
|
16
|
+
exclude:
|
17
|
+
- rvm: 2.0.0
|
18
|
+
env: RAILS_VERSION=5
|
19
|
+
- rvm: 2.1.0
|
20
|
+
env: RAILS_VERSION=5
|
21
|
+
- rvm: 2.2.0
|
22
|
+
env: RAILS_VERSION=5
|
23
|
+
before_install: gem install bundler -v 1.12.5
|
24
|
+
before_script:
|
25
|
+
- cp config/database.travis.yml config/database.yml
|
26
|
+
- bin/setup
|
27
|
+
script: bundle exec rspec
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Justin Aiken
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
[![Gem Version](http://img.shields.io/gem/v/full_table_scan_matchers.svg)](https://rubygems.org/gems/full_table_scan_matchers)[![Build Status](http://img.shields.io/travis/JustinAiken/full_table_scan_matchers/master.svg)](http://travis-ci.org/JustinAiken/full_table_scan_matchers)[![Coveralls branch](http://img.shields.io/coveralls/JustinAiken/full_table_scan_matchers/master.svg)](https://coveralls.io/r/JustinAiken/full_table_scan_matchers?branch=master)
|
2
|
+
|
3
|
+
# full_table_scan_matchers
|
4
|
+
|
5
|
+
Detect full table scans in your unit tests! As opposed to just doing basic regexes on the `db/schema.rb` like [rails-best-practices](https://github.com/railsbp/rails_best_practices) does, this actually checks queries made against the database, to ensure and assert that there are indexes for it to use.
|
6
|
+
|
7
|
+
## Requirements/Support
|
8
|
+
|
9
|
+
- Ruby 2.0+
|
10
|
+
- ActiveRecord 4+
|
11
|
+
- ActiveSupport 4+
|
12
|
+
- mysql2 adapter
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add to your `Gemfile`, in the test group:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
group :test do
|
20
|
+
gem 'full_table_scan_matchers', github: 'JustinAiken/full_table_scan_matchers'
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
# No full table scans at all please:
|
28
|
+
expect { user.posts }.not_to full_table_scan
|
29
|
+
|
30
|
+
# Or on just a specific thing:
|
31
|
+
expect {
|
32
|
+
user.posts.joins(:comments).first.comments
|
33
|
+
}.not_to full_table_scan.on :posts
|
34
|
+
```
|
35
|
+
|
36
|
+
## How's it work?
|
37
|
+
|
38
|
+
- It logs all SQL queries made inside the `expect` block
|
39
|
+
- ..optionally filtering them to table(s) you care about
|
40
|
+
- Afterwards, it runs all those through `EXPLAIN`
|
41
|
+
- Instead of checking `type` for `ALL`, it checks the keys instead
|
42
|
+
- Because in test mode, mysql may ignore the index and scan the whole table because it's so small
|
43
|
+
- But your production database is much, much larger - we just want to make sure that indexes are available
|
44
|
+
|
45
|
+
## Configuration
|
46
|
+
|
47
|
+
You can optionally configure a few things:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
FullTableScanMatchers.configure do |config|
|
51
|
+
# Tables to ignore - defaults to none
|
52
|
+
# Default: none
|
53
|
+
config.ignores = []
|
54
|
+
|
55
|
+
# Database adapter to use - only one for now
|
56
|
+
# Default (and only): mysql
|
57
|
+
config.adapter = FullTableScanMatchers::DBAdapters::MySql
|
58
|
+
|
59
|
+
# Includes a backtrace in the fail output if this is set to true
|
60
|
+
# Default: false
|
61
|
+
config.log_backtrace = false
|
62
|
+
|
63
|
+
# Add a proc to strip things from the logged backtraces
|
64
|
+
# Default: None
|
65
|
+
config.backtrace_filter = Proc.new { |backtrace| backtrace }
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
## Postgres?
|
70
|
+
|
71
|
+
Currently, this just support mySql. However, I tried to keep the part that's most-tied to that database (parsing the `EXPLAIN` output) silo'd in an adapter - I'd happily merge any clean PRs that add Postgres (or others)!
|
72
|
+
|
73
|
+
## Development
|
74
|
+
|
75
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
|
76
|
+
|
77
|
+
## Credits
|
78
|
+
|
79
|
+
- Primary author: [@JustinAiken](https://github.com/JustinAiken)
|
80
|
+
- A **lot** of inspiration comes from the excellent [db-query-matchers](https://github.com/brigade/db-query-matchers) by [@brigade](https://github.com/brigade)
|
81
|
+
|
82
|
+
## Contributing
|
83
|
+
|
84
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/JustinAiken/full_table_scan_matchers.
|
85
|
+
|
86
|
+
## License
|
87
|
+
|
88
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
task default: :spec
|
7
|
+
|
8
|
+
require 'active_record'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
namespace :db do
|
12
|
+
db_config = YAML::load(File.open('config/database.yml'))['test']
|
13
|
+
db_config_admin = db_config.merge('database' => 'mysql')
|
14
|
+
|
15
|
+
desc "Create the database"
|
16
|
+
task :create do
|
17
|
+
ActiveRecord::Base.establish_connection(db_config_admin)
|
18
|
+
ActiveRecord::Base.connection.create_database(db_config["database"])
|
19
|
+
puts "Database created."
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Drop the database"
|
23
|
+
task :drop do
|
24
|
+
ActiveRecord::Base.establish_connection(db_config_admin)
|
25
|
+
ActiveRecord::Base.connection.drop_database(db_config["database"])
|
26
|
+
puts "Database deleted."
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Reset the database"
|
30
|
+
task reset: [:drop, :create]
|
31
|
+
end
|
data/bin/setup
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'full_table_scan_matchers/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "full_table_scan_matchers"
|
8
|
+
spec.version = FullTableScanMatchers::VERSION
|
9
|
+
spec.authors = ["Justin Aiken"]
|
10
|
+
spec.email = ["60tonangel@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Matchers for rspec to detect full table scans}
|
13
|
+
spec.description = %q{Matchers for rspec to detect full table scans}
|
14
|
+
spec.homepage = "https://github.com/JustinAiken/full_table_scan_matchers"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^spec/}) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "activesupport", ">= 3.0"
|
21
|
+
spec.add_dependency "activerecord", ">= 3.0"
|
22
|
+
|
23
|
+
spec.add_development_dependency 'mysql2'
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
spec.add_development_dependency 'coveralls'
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'full_table_scan_matchers/version'
|
2
|
+
require 'full_table_scan_matchers/db_adapters'
|
3
|
+
require 'full_table_scan_matchers/db_adapters/mysql'
|
4
|
+
require 'full_table_scan_matchers/db_adapters/mysql/explain_result'
|
5
|
+
require 'full_table_scan_matchers/sql_watcher'
|
6
|
+
require 'full_table_scan_matchers/matchers/full_table_scan'
|
7
|
+
require 'full_table_scan_matchers/configuration'
|
8
|
+
|
9
|
+
require 'active_record'
|
10
|
+
require 'active_support'
|
11
|
+
|
12
|
+
# Main module that holds global configuration.
|
13
|
+
module FullTableScanMatchers
|
14
|
+
class << self
|
15
|
+
attr_writer :configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
# Gets the current configuration
|
19
|
+
# @return [FullTableScanMatchers::Configuration] the active configuration
|
20
|
+
def self.configuration
|
21
|
+
@configuration ||= Configuration.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# Resets the current configuration.
|
25
|
+
# @return [FullTableScanMatchers::Configuration] the active configuration
|
26
|
+
def self.reset_configuration
|
27
|
+
@configuration = Configuration.new
|
28
|
+
end
|
29
|
+
|
30
|
+
# Updates the current configuration.
|
31
|
+
# @example
|
32
|
+
# FullTableScanMatchers.configure do |config|
|
33
|
+
# config.ignores = [/SELECT.*FROM.*users/]
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
def self.configure
|
37
|
+
yield configuration
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FullTableScanMatchers
|
2
|
+
|
3
|
+
# Configuration for the FullTableScanMatchers module.
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :ignores, :adapter, :log_backtrace, :backtrace_filter
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@ignores = []
|
9
|
+
@adapter = DBAdapters::MySql
|
10
|
+
@log_backtrace = false
|
11
|
+
@backtrace_filter = Proc.new { |backtrace| backtrace }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module FullTableScanMatchers
|
4
|
+
module DBAdapters
|
5
|
+
module MySql
|
6
|
+
class ExplainResult
|
7
|
+
attr_accessor :sql_statement, :structs, :backtrace, :tables
|
8
|
+
|
9
|
+
def initialize(sql_statement, backtrace: nil, tables: nil)
|
10
|
+
@sql_statement = sql_statement
|
11
|
+
@backtrace = backtrace
|
12
|
+
@tables = tables
|
13
|
+
end
|
14
|
+
|
15
|
+
def full_table_scan?
|
16
|
+
offending_structs.any?
|
17
|
+
end
|
18
|
+
|
19
|
+
def structs
|
20
|
+
@structs ||= as_hashes.map { |hash| OpenStruct.new hash }
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
[
|
25
|
+
"SQL: #{sql_statement}",
|
26
|
+
structs.map do |struct|
|
27
|
+
(offending_structs.include?(struct) ? "FAIL: " : "INFO: ") +
|
28
|
+
struct.to_h.map { |k, v| "#{k}: #{v}" }.join(", ")
|
29
|
+
end,
|
30
|
+
(backtrace.present? ? "BACKTRACE: #{backtrace}" : nil)
|
31
|
+
].flatten.compact.join "\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def offending_structs
|
37
|
+
structs
|
38
|
+
.reject { |struct| struct.table == "NULL" }
|
39
|
+
.select { |struct| tables.nil? || Array(tables).map(&:to_s).include?(struct.table) }
|
40
|
+
.select { |struct| struct.key == "NULL" && struct.possible_keys == "NULL" }
|
41
|
+
end
|
42
|
+
|
43
|
+
def as_hashes
|
44
|
+
keys = explain_rows.shift.map(&:downcase)
|
45
|
+
explain_rows.map { |values| Hash[keys.zip(values)].symbolize_keys! }
|
46
|
+
end
|
47
|
+
|
48
|
+
def explain_rows
|
49
|
+
@explain_rows ||= explained_result
|
50
|
+
.reject { |row| row =~ /^\s*\+/ } # Reject table frames, like: +----+-------------+
|
51
|
+
.reject { |row| row =~ / rows? in set/ } # Reject "1 row in set" type things after result
|
52
|
+
.map { |row| row.split("|").map(&:strip).reject &:blank? }
|
53
|
+
end
|
54
|
+
|
55
|
+
def explained_result
|
56
|
+
@explained_result ||= ActiveRecord::Base.connection.explain(sql_statement).split("\n")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'rspec/core'
|
2
|
+
require 'rspec/expectations'
|
3
|
+
require 'rspec/mocks'
|
4
|
+
|
5
|
+
RSpec::Matchers.define :full_table_scan do |options = {}|
|
6
|
+
if RSpec::Core::Version::STRING =~ /^2/
|
7
|
+
def self.failure_message_when_negated(&block)
|
8
|
+
failure_message_for_should_not(&block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.failure_message(&block)
|
12
|
+
failure_message_for_should(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def supports_block_expectations?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
else
|
19
|
+
supports_block_expectations
|
20
|
+
end
|
21
|
+
|
22
|
+
# Taken from ActionView::Helpers::TextHelper
|
23
|
+
def pluralize(count, singular, plural = nil)
|
24
|
+
word = if count == 1 || count =~ /^1(\.0+)?$/
|
25
|
+
singular
|
26
|
+
else
|
27
|
+
plural || singular.pluralize
|
28
|
+
end
|
29
|
+
|
30
|
+
"#{count || 0} #{word}"
|
31
|
+
end
|
32
|
+
|
33
|
+
chain :on do |tables|
|
34
|
+
@tables = tables
|
35
|
+
end
|
36
|
+
|
37
|
+
define_method :matches? do |block|
|
38
|
+
watcher_option = {}
|
39
|
+
watcher_option[:tables] = Array(@tables) if defined?(@tables)
|
40
|
+
@watcher = FullTableScanMatchers::SQLWatcher.new(watcher_option)
|
41
|
+
ActiveSupport::Notifications.subscribed @watcher.to_proc, 'sql.active_record', &block
|
42
|
+
|
43
|
+
replay_logged_with_explain!
|
44
|
+
|
45
|
+
@watcher.count > 0
|
46
|
+
end
|
47
|
+
|
48
|
+
def replay_logged_with_explain!
|
49
|
+
@watcher.log
|
50
|
+
.map! { |logged| FullTableScanMatchers.configuration.adapter::ExplainResult.new(logged[:sql], backtrace: logged[:backtrace], tables: @tables) }
|
51
|
+
.reject! { |logged| !logged.full_table_scan? }
|
52
|
+
end
|
53
|
+
|
54
|
+
def output_offenders
|
55
|
+
@watcher.log.map(&:to_s).join("\n")
|
56
|
+
end
|
57
|
+
|
58
|
+
failure_message_when_negated do |_|
|
59
|
+
<<-EOS
|
60
|
+
expected no full table scans, but #{@watcher.log.count} were made:
|
61
|
+
#{output_offenders}
|
62
|
+
EOS
|
63
|
+
end
|
64
|
+
|
65
|
+
failure_message do |_|
|
66
|
+
if options[:count]
|
67
|
+
expected = pluralize(options[:count], 'full table scan')
|
68
|
+
actual = pluralize(@watcher.count, 'was', 'were')
|
69
|
+
|
70
|
+
output = "expected #{expected}, but #{actual} made"
|
71
|
+
if @watcher.count > 0
|
72
|
+
output += ":\n#{output_offenders}"
|
73
|
+
end
|
74
|
+
output
|
75
|
+
else
|
76
|
+
'expected full table scans, but none were made'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module FullTableScanMatchers
|
2
|
+
class SQLWatcher
|
3
|
+
attr_reader :log, :options
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@log = []
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
# Turns a SQLWatcher instance into a lambda. Designed to be used when
|
11
|
+
# subscribing to events through the ActiveSupport::Notifications module.
|
12
|
+
#
|
13
|
+
# @return [Proc]
|
14
|
+
def to_proc
|
15
|
+
lambda &method(:callback)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Method called from the ActiveSupport::Notifications module (through the
|
19
|
+
# lambda created by `to_proc`) when an SQL query is made.
|
20
|
+
#
|
21
|
+
# @param _name [String] name of the event
|
22
|
+
# @param _start [Time] when the instrumented block started execution
|
23
|
+
# @param _finish [Time] when the instrumented block ended execution
|
24
|
+
# @param _message_id [String] unique ID for this notification
|
25
|
+
# @param payload [Hash] the payload
|
26
|
+
#
|
27
|
+
def callback(_name, _start, _finish, _message_id, payload)
|
28
|
+
sql_statement = payload[:sql]
|
29
|
+
return if sql_statement =~ /EXPLAIN /i # That's from us, don't EXPLAIN the EXPLAINS!
|
30
|
+
return unless sql_statement =~ /SELECT / # Only selects for now
|
31
|
+
return if any_match? ignores, sql_statement
|
32
|
+
return unless any_match? tables, sql_statement if options[:tables]
|
33
|
+
|
34
|
+
backtrace = if FullTableScanMatchers.configuration.log_backtrace
|
35
|
+
raw_backtrace = caller
|
36
|
+
filtered_backtrace = FullTableScanMatchers.configuration.backtrace_filter.call(raw_backtrace)
|
37
|
+
"#{filtered_backtrace.join("\n")}\n"
|
38
|
+
else
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
@log << {sql: sql_statement.strip, backtrace: backtrace}
|
43
|
+
end
|
44
|
+
|
45
|
+
def count
|
46
|
+
log.count
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def tables
|
52
|
+
Array(options[:tables]).map { |table_name| /(FROM|JOIN)\s+`?#{table_name.to_s}`?/i }
|
53
|
+
end
|
54
|
+
|
55
|
+
def ignores
|
56
|
+
FullTableScanMatchers.configuration.ignores
|
57
|
+
end
|
58
|
+
|
59
|
+
def any_match?(patterns, sql)
|
60
|
+
patterns.any? { |pattern| sql =~ pattern }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: full_table_scan_matchers
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Justin Aiken
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mysql2
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.12'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.12'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: coveralls
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Matchers for rspec to detect full table scans
|
112
|
+
email:
|
113
|
+
- 60tonangel@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rspec"
|
120
|
+
- ".travis.yml"
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- bin/setup
|
126
|
+
- config/database.travis.yml
|
127
|
+
- full_table_scan_matchers.gemspec
|
128
|
+
- lib/full_table_scan_matchers.rb
|
129
|
+
- lib/full_table_scan_matchers/configuration.rb
|
130
|
+
- lib/full_table_scan_matchers/db_adapters.rb
|
131
|
+
- lib/full_table_scan_matchers/db_adapters/mysql.rb
|
132
|
+
- lib/full_table_scan_matchers/db_adapters/mysql/explain_result.rb
|
133
|
+
- lib/full_table_scan_matchers/matchers/full_table_scan.rb
|
134
|
+
- lib/full_table_scan_matchers/sql_watcher.rb
|
135
|
+
- lib/full_table_scan_matchers/version.rb
|
136
|
+
homepage: https://github.com/JustinAiken/full_table_scan_matchers
|
137
|
+
licenses:
|
138
|
+
- MIT
|
139
|
+
metadata: {}
|
140
|
+
post_install_message:
|
141
|
+
rdoc_options: []
|
142
|
+
require_paths:
|
143
|
+
- lib
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
145
|
+
requirements:
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 2.6.6
|
157
|
+
signing_key:
|
158
|
+
specification_version: 4
|
159
|
+
summary: Matchers for rspec to detect full table scans
|
160
|
+
test_files: []
|