rdavila-query_reviewer 0.1.0
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.
- data/MIT-LICENSE +20 -0
- data/README +51 -0
- data/Rakefile +22 -0
- data/init.rb +13 -0
- data/lib/query_reviewer.rb +51 -0
- data/lib/query_reviewer/array_extensions.rb +29 -0
- data/lib/query_reviewer/controller_extensions.rb +60 -0
- data/lib/query_reviewer/mysql_adapter_extensions.rb +90 -0
- data/lib/query_reviewer/mysql_analyzer.rb +62 -0
- data/lib/query_reviewer/query_warning.rb +17 -0
- data/lib/query_reviewer/sql_query.rb +130 -0
- data/lib/query_reviewer/sql_query_collection.rb +103 -0
- data/lib/query_reviewer/sql_sub_query.rb +44 -0
- data/lib/query_reviewer/views/_box.rhtml +11 -0
- data/lib/query_reviewer/views/_box_ajax.js +34 -0
- data/lib/query_reviewer/views/_box_body.rhtml +73 -0
- data/lib/query_reviewer/views/_box_disabled.rhtml +2 -0
- data/lib/query_reviewer/views/_box_header.rhtml +1 -0
- data/lib/query_reviewer/views/_box_includes.rhtml +297 -0
- data/lib/query_reviewer/views/_explain.rhtml +30 -0
- data/lib/query_reviewer/views/_profile.rhtml +26 -0
- data/lib/query_reviewer/views/_query_sql.rhtml +8 -0
- data/lib/query_reviewer/views/_query_trace.rhtml +31 -0
- data/lib/query_reviewer/views/_query_with_warning.rhtml +54 -0
- data/lib/query_reviewer/views/_spectrum.rhtml +10 -0
- data/lib/query_reviewer/views/_warning_no_query.rhtml +8 -0
- data/lib/query_reviewer/views/query_review_box_helper.rb +97 -0
- data/query_reviewer_defaults.yml +39 -0
- data/rails/init.rb +13 -0
- data/tasks/query_reviewer_tasks.rake +7 -0
- data/test/sql_query_test.rb +8 -0
- data/test/sql_sub_query_test.rb +17 -0
- data/test/test_helper.rb +18 -0
- metadata +97 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
<table class="explain">
|
2
|
+
<thead>
|
3
|
+
<tr>
|
4
|
+
<th>table</th>
|
5
|
+
<th>select_type</th>
|
6
|
+
<th>type</th>
|
7
|
+
<th>extra</th>
|
8
|
+
<th>possible_keys</th>
|
9
|
+
<th>key</th>
|
10
|
+
<th>key length</th>
|
11
|
+
<th>ref</th>
|
12
|
+
<th>rows</th>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody>
|
16
|
+
<% query.subqueries.each do |subquery| %>
|
17
|
+
<tr>
|
18
|
+
<td title="<%= h subquery.table %>"><%= h subquery.table %></td>
|
19
|
+
<td title="<%= h subquery.select_type %>"><%= h subquery.select_type %></td>
|
20
|
+
<td title="<%= h subquery.query_type %>"><%= h subquery.query_type %></td>
|
21
|
+
<td title="<%= h subquery.extra %>"><%= h subquery.extra %></td>
|
22
|
+
<td title="<%= h subquery.possible_keys %>"><%= h subquery.possible_keys %></td>
|
23
|
+
<td title="<%= h subquery.key %>"><%= h subquery.key %></td>
|
24
|
+
<td title="<%= h subquery.key_len %>"><%= h subquery.key_len %></td>
|
25
|
+
<td title="<%= h subquery.ref %>"><%= h subquery.ref %></td>
|
26
|
+
<td title="<%= h subquery.rows %>"><%= h subquery.rows %></td>
|
27
|
+
</tr>
|
28
|
+
<% end %>
|
29
|
+
</tbody>
|
30
|
+
</table>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<table>
|
2
|
+
<thead>
|
3
|
+
<tr>
|
4
|
+
<th>stage</th>
|
5
|
+
<th>duration</th>
|
6
|
+
<th>user cpu</th>
|
7
|
+
<th>context switches</th>
|
8
|
+
<th>block ops</th>
|
9
|
+
<th>messages</th>
|
10
|
+
<th>page faults</th>
|
11
|
+
</tr>
|
12
|
+
</thead>
|
13
|
+
<tbody>
|
14
|
+
<% query.profile.each do |profile| %>
|
15
|
+
<tr>
|
16
|
+
<td title="<%= h profile.Status %>"><%= h profile.Status %></td>
|
17
|
+
<td title="<%= h profile.Duration %> seconds"><%= h("%.4f" % profile.Duration.to_f) %>s</td>
|
18
|
+
<td title="USER: <%= profile.CPU_user.to_f %>s SYSTEM: <%= profile.CPU_system.to_f %>s"><%= h("%.4f" % profile.CPU_user.to_f) %>s</td>
|
19
|
+
<td title="Voluntary: <%= h profile.Context_voluntary %> Involuntary: <%= h profile.Context_involuntary %>"><%= h(profile.Context_voluntary.to_i + profile.Context_involuntary.to_i) %></td>
|
20
|
+
<td title="Ops in: <%= h profile.Block_ops_in %> Ops out: <%= h profile.Block_ops_out %>"><%= h(profile.Block_ops_in.to_i + profile.Block_ops_out.to_i) %></td>
|
21
|
+
<td title="Sent: <%= h profile.Messages_sent %> Received: <%= h profile.Messages_received %>"><%= h(profile.Messages_sent.to_i + profile.Messages_received.to_i) %></td>
|
22
|
+
<td title="Major: <%= h profile.Page_faults_major %> Minor: <%= h profile.Page_faults_minor %>"><%= h profile.Page_faults_major %></td>
|
23
|
+
<tr>
|
24
|
+
<% end %>
|
25
|
+
</tbody>
|
26
|
+
</table>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<span id="query_plain_sql_<%= query_sql.id %>" style="display: none;">
|
2
|
+
<%= syntax_highlighted_sql(query_sql.sql) %>
|
3
|
+
<% if query_sql.respond_to?(:subqueries) && query_sql.subqueries.length > 1 %>
|
4
|
+
<% end %>
|
5
|
+
</span>
|
6
|
+
<span id="query_sanitized_sql_<%= query_sql.id %>">
|
7
|
+
<%= syntax_highlighted_sql(query_sql.sanitized_sql) if query_sql.sanitized_sql %>
|
8
|
+
</span>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<div class="trace" id="trace_<%= query_id %>_abridged">
|
2
|
+
<code>
|
3
|
+
<% query_trace[0..(QueryReviewer::CONFIGURATION["stack_trace_lines"] - 1)].compact.each do |c| %>
|
4
|
+
<% if c.match(/:.*:/) %>
|
5
|
+
<% file = h(c.slice(0..(c.index(":", c.index(":")+1)-1))) %>
|
6
|
+
<span><%= file.split("/")[0..-2].join("/") %>/</span><span class="bold"><%= file.split("/").last %></span>
|
7
|
+
<br/>
|
8
|
+
<span class="indent"><%= h(c.slice((c.index(":", c.index(":")+1)+1)..-1)) %></span><br/>
|
9
|
+
<% else %>
|
10
|
+
<span><%= h c %></span><br/>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
</code>
|
14
|
+
<a href="javascript: query_review_toggle('trace_<%= query_id %>_abridged'); query_review_toggle('trace_<%= query_id %>_full')" title="show full trace">FULL</a>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<div class="trace" style="display: none; max-height: 300px; overflow: scroll" id="trace_<%= query_id %>_full">
|
18
|
+
<code>
|
19
|
+
<% full_trace.compact.each do |c| %>
|
20
|
+
<% if c.match(/:.*:/) %>
|
21
|
+
<% file = h(c.slice(0..(c.index(":", c.index(":")+1)-1))) %>
|
22
|
+
<span><%= file.split("/")[0..-2].join("/") %>/</span><span class="bold"><%= file.split("/").last %></span>
|
23
|
+
<br/>
|
24
|
+
<span class="indent"><%= h(c.slice((c.index(":", c.index(":")+1)+1)..-1)) %></span><br/>
|
25
|
+
<% else %>
|
26
|
+
<span><%= h c %></span><br/>
|
27
|
+
<% end %>
|
28
|
+
<% end %>
|
29
|
+
</code>
|
30
|
+
<a href="javascript: query_review_toggle('trace_<%= query_id %>_abridged'); query_review_toggle('trace_<%= query_id %>_full')" title="show short trace">SHORT</a>
|
31
|
+
</div>
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<li id="query_<%= query_with_warning.id %>">
|
2
|
+
<div>
|
3
|
+
<%= render :partial => "/spectrum", :locals => {:severity => query_with_warning.max_severity} %>
|
4
|
+
<% if QueryReviewer::CONFIGURATION["production_data"] %>
|
5
|
+
<div style="float: left; padding-right: 5px;">
|
6
|
+
<%= duration_with_color(query_with_warning) %>s
|
7
|
+
</div>
|
8
|
+
<% end %>
|
9
|
+
<p>
|
10
|
+
<% if query_with_warning.count > 1 %>
|
11
|
+
<b title="<%= query_with_warning.count %> queries were executed with the same stack trace and similar SQL structure">
|
12
|
+
<%= query_with_warning.count %> identical queries
|
13
|
+
</b>
|
14
|
+
<% end %>
|
15
|
+
<i>Table <%= (query_with_warning.warnings.detect {|w| !w.table.blank? } || query_with_warning.warnings.last).table %>:</i>
|
16
|
+
<% query_with_warning.warnings.sort{|a,b| a.severity <=> b.severity}.reverse.each_with_index do |warn, index| %>
|
17
|
+
<span style="color: <%= severity_color warn.severity%>;" title="<%= warn.desc%>"><%= warn.problem %></span><%= ", " if index < query_with_warning.warnings.length - 1 %>
|
18
|
+
<% end %>
|
19
|
+
<a href="javascript: query_review_toggle('warning_<%= query_with_warning.id %>_desc')" title="show/hide warning message">MSG</a>
|
20
|
+
<a href="javascript: query_review_toggle('warning_<%= query_with_warning.id %>_sql')" title="show/hide sql">SQL</a>
|
21
|
+
<% if query_with_warning.select? %>
|
22
|
+
<a href="javascript: query_review_toggle('warning_<%= query_with_warning.id %>_explain')" title="show/hide explain output">EXPLN</a>
|
23
|
+
<% end %>
|
24
|
+
<% if QueryReviewer::CONFIGURATION["profiling"] && query_with_warning.profile %>
|
25
|
+
<a href="javascript: query_review_toggle('warning_<%= query_with_warning.id %>_profile')" title="show/hide profile output">PROF</a>
|
26
|
+
<% end %>
|
27
|
+
<a href="javascript: query_review_toggle('warning_<%= query_with_warning.id %>_trace')" title="show/hide stack trace">TRACE</a>
|
28
|
+
<% if ignore_hash?(query_with_warning.to_hash) %>
|
29
|
+
<a href="javascript: remove_ignore_hash('<%= query_with_warning.to_hash %>'); query_review_hide('query_<%= query_with_warning.id %>')" title="stop ignore this query from now on">UNIGNR</a>
|
30
|
+
<% else %>
|
31
|
+
<a href="javascript: add_ignore_hash('<%= query_with_warning.to_hash %>'); query_review_hide('query_<%= query_with_warning.id %>')" title="ignoring this query from now on">IGNR</a>
|
32
|
+
<% end %>
|
33
|
+
</p>
|
34
|
+
</div>
|
35
|
+
<p style="display: none" id="warning_<%= query_with_warning.id %>_desc" class="indent">
|
36
|
+
<% query_with_warning.warnings.each do |warn| %>
|
37
|
+
<span style="color: <%= severity_color warn.severity%>"><%= warn.desc %></span><br/>
|
38
|
+
<% end %>
|
39
|
+
</p>
|
40
|
+
<p style="display: none" id="warning_<%= query_with_warning.id %>_sql" class="indent small tbpadded">
|
41
|
+
<%= render :partial => "/query_sql", :object => query_with_warning %>
|
42
|
+
</p>
|
43
|
+
<div style="display: none" id="warning_<%= query_with_warning.id %>_explain" class="indent small tbpadded">
|
44
|
+
<%= render :partial => "/explain", :locals => {:query => query_with_warning} %>
|
45
|
+
</div>
|
46
|
+
<% if QueryReviewer::CONFIGURATION["profiling"] && query_with_warning.profile %>
|
47
|
+
<div style="display: none" id="warning_<%= query_with_warning.id %>_profile" class="indent small tbpadded">
|
48
|
+
<%= render :partial => "/profile", :locals => {:query => query_with_warning} %>
|
49
|
+
</div>
|
50
|
+
<% end %>
|
51
|
+
<div style="display: none" id="warning_<%= query_with_warning.id %>_trace" class="indent small">
|
52
|
+
<%= render :partial => "/query_trace", :object => query_with_warning.relevant_trace, :locals => {:query_id => query_with_warning.id, :full_trace => query_with_warning.full_trace} %>
|
53
|
+
</div>
|
54
|
+
</li>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div class="spectrum_container" title="Severity: <%= severity%> out of 10">
|
2
|
+
<% 0.upto(15) do |i| %>
|
3
|
+
<div class="spectrum_elem" style="background-color: <%= "##{i.to_s(16)}F0"%>"></div>
|
4
|
+
<% end %>
|
5
|
+
<% 0.upto(15) do |i| %>
|
6
|
+
<div class="spectrum_elem" style="background-color: <%= "#F#{((15-i)).to_s(16)}0"%>"></div>
|
7
|
+
<% end %>
|
8
|
+
<div class="spectrum_elem" style="background-color: #FF0000"></div>
|
9
|
+
<div class="spectrum_pointer" style="left: <%= severity * 3 + 2 %>px;"></div>
|
10
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<li id="warning_<%= warning_no_query.id %>">
|
2
|
+
<div>
|
3
|
+
<%= render :partial => "/spectrum", :locals => {:severity => warning_no_query.severity} %>
|
4
|
+
<p>
|
5
|
+
<span style="color: <%= severity_color warning_no_query.severity%>" title="<%= warning_no_query.desc %>"><%= warning_no_query.problem %></span>
|
6
|
+
</p>
|
7
|
+
</div>
|
8
|
+
</li>
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module QueryReviewer
|
2
|
+
module Views
|
3
|
+
module QueryReviewBoxHelper
|
4
|
+
def parent_div_class
|
5
|
+
"sql_#{parent_div_status.downcase}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def parent_div_status
|
9
|
+
if !enabled_by_cookie
|
10
|
+
"DISABLED"
|
11
|
+
elsif overall_max_severity < (QueryReviewer::CONFIGURATION["warn_severity"] || 4)
|
12
|
+
"OK"
|
13
|
+
elsif overall_max_severity < (QueryReviewer::CONFIGURATION["critical_severity"] || 7)
|
14
|
+
# uh oh
|
15
|
+
"WARNING"
|
16
|
+
else
|
17
|
+
# oh @#&!
|
18
|
+
"CRITICAL"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def syntax_highlighted_sql(sql)
|
23
|
+
if QueryReviewer::CONFIGURATION["uv"]
|
24
|
+
uv_out = Uv.parse(sql, "xhtml", "sql_rails", false, "blackboard")
|
25
|
+
uv_out.gsub("<pre class=\"blackboard\">", "<code class=\"sql\">").gsub("</pre>", "</code>")
|
26
|
+
else
|
27
|
+
sql
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def overall_max_severity
|
32
|
+
max = 0
|
33
|
+
max = queries_with_warnings_sorted_nonignored[0].max_severity unless queries_with_warnings_sorted_nonignored.empty?
|
34
|
+
max = warnings_no_query_sorted.first.severity unless warnings_no_query_sorted.empty? || warnings_no_query_sorted.first.severity < max
|
35
|
+
max
|
36
|
+
end
|
37
|
+
|
38
|
+
def severity_color(severity)
|
39
|
+
red = (severity * 16.0 / 10).to_i
|
40
|
+
green = ((10-severity) * 16.0 / 10).to_i
|
41
|
+
red = 8 if red > 8
|
42
|
+
red = 0 if red < 0
|
43
|
+
green = 8 if green > 8
|
44
|
+
green = 0 if green < 0
|
45
|
+
"##{red.to_s(16)}#{green.to_s(16)}0"
|
46
|
+
end
|
47
|
+
|
48
|
+
def ignore_hash?(h)
|
49
|
+
(@controller.send(:cookies)["query_review_ignore_list"] || "").split(",").include?(h.to_s)
|
50
|
+
end
|
51
|
+
|
52
|
+
def queries_with_warnings
|
53
|
+
@queries.queries.select{|q| q.has_warnings?}
|
54
|
+
end
|
55
|
+
|
56
|
+
def queries_with_warnings_sorted
|
57
|
+
queries_with_warnings.sort{|a,b| (b.max_severity * 1000 + (b.duration || 0)) <=> (a.max_severity * 1000 + (a.duration || 0))}
|
58
|
+
end
|
59
|
+
|
60
|
+
def queries_with_warnings_sorted_nonignored
|
61
|
+
queries_with_warnings_sorted.select{|q| q.max_severity >= ::QueryReviewer::CONFIGURATION["warn_severity"] && !ignore_hash?(q.to_hash)}
|
62
|
+
end
|
63
|
+
|
64
|
+
def queries_with_warnings_sorted_ignored
|
65
|
+
queries_with_warnings_sorted.reject{|q| q.max_severity >= ::QueryReviewer::CONFIGURATION["warn_severity"] && !ignore_hash?(q.to_hash)}
|
66
|
+
end
|
67
|
+
|
68
|
+
def warnings_no_query_sorted
|
69
|
+
@queries.collection_warnings.sort{|a,b| a.severity <=> b.severity}.reverse
|
70
|
+
end
|
71
|
+
|
72
|
+
def warnings_no_query_sorted_ignored
|
73
|
+
warnings_no_query_sorted.select{|q| q.severity < ::QueryReviewer::CONFIGURATION["warn_severity"]}
|
74
|
+
end
|
75
|
+
|
76
|
+
def warnings_no_query_sorted_nonignored
|
77
|
+
warnings_no_query_sorted.select{|q| q.severity >= ::QueryReviewer::CONFIGURATION["warn_severity"]}
|
78
|
+
end
|
79
|
+
|
80
|
+
def enabled_by_cookie
|
81
|
+
@controller.send(:cookies)["query_review_enabled"]
|
82
|
+
end
|
83
|
+
|
84
|
+
def duration_with_color(query)
|
85
|
+
title = query.duration_stats
|
86
|
+
duration = query.duration
|
87
|
+
if duration > QueryReviewer::CONFIGURATION["critical_duration_threshold"]
|
88
|
+
"<span style=\"color: #{severity_color(9)}\" title=\"#{title}\">#{"%.3f" % duration}</span>"
|
89
|
+
elsif duration > QueryReviewer::CONFIGURATION["warn_duration_threshold"]
|
90
|
+
"<span style=\"color: #{severity_color(QueryReviewer::CONFIGURATION["critical_severity"])}\" title=\"#{title}\">#{"%.3f" % duration}</span>"
|
91
|
+
else
|
92
|
+
"<span title=\"#{title}\">#{"%.3f" % duration}</span>"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
all:
|
2
|
+
inject_view: true
|
3
|
+
stack_trace_lines: 3
|
4
|
+
trace_includes_vendor: false
|
5
|
+
trace_includes_lib: true
|
6
|
+
profiling: enabled
|
7
|
+
production_data: true
|
8
|
+
max_safe_key_length: 100
|
9
|
+
disable_sql_cache: true
|
10
|
+
|
11
|
+
warn_severity: 3
|
12
|
+
critical_severity: 7
|
13
|
+
|
14
|
+
warn_select_count: 20
|
15
|
+
critical_select_count: 50
|
16
|
+
|
17
|
+
warn_update_count: 5
|
18
|
+
critical_update_count: 10
|
19
|
+
|
20
|
+
warn_insert_count: 5
|
21
|
+
critical_insert_count: 10
|
22
|
+
|
23
|
+
warn_delete_count: 5
|
24
|
+
critical_delete_count: 10
|
25
|
+
|
26
|
+
warn_duration_threshold: 0.2
|
27
|
+
critical_duration_threshold: 1.0
|
28
|
+
|
29
|
+
warn_affected_rows: 10
|
30
|
+
critical_affected_rows: 100
|
31
|
+
|
32
|
+
development:
|
33
|
+
enabled: true
|
34
|
+
|
35
|
+
production:
|
36
|
+
enabled: false
|
37
|
+
|
38
|
+
test:
|
39
|
+
enabled: false
|
data/rails/init.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Include hook code here
|
2
|
+
|
3
|
+
require 'query_reviewer'
|
4
|
+
|
5
|
+
if QueryReviewer.enabled?
|
6
|
+
ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:include, QueryReviewer::MysqlAdapterExtensions)
|
7
|
+
ActionController::Base.send(:include, QueryReviewer::ControllerExtensions)
|
8
|
+
Array.send(:include, QueryReviewer::ArrayExtensions)
|
9
|
+
|
10
|
+
if ActionController::Base.respond_to?(:append_view_path)
|
11
|
+
ActionController::Base.append_view_path(File.dirname(__FILE__) + "/lib/query_reviewer/views")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# desc "Explaining what the task does"
|
2
|
+
namespace :query_reviewer do
|
3
|
+
desc "Create a default config/query_reviewer.yml"
|
4
|
+
task :setup do
|
5
|
+
FileUtils.copy(File.join(File.dirname(__FILE__), "..", "query_reviewer_defaults.yml"), File.join(RAILS_ROOT, "config", "query_reviewer.yml"))
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class SqlSubqueryTest < Test::Unit::TestCase
|
4
|
+
def test_analyze_select_type
|
5
|
+
query = get_query(:select_type => "DEPENDENT UNION")
|
6
|
+
query.send :analyze_select_type!
|
7
|
+
query.should_warn("DEPENDENT UNION", 2)
|
8
|
+
|
9
|
+
query = get_query(:select_type => "UNCACHEABLE SUBQUERY")
|
10
|
+
query.send :analyze_select_type!
|
11
|
+
query.should_warn("UNCACHEABLE SUBQUERY", 10)
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_query(options)
|
15
|
+
SqlSubQuery.new(options)
|
16
|
+
end
|
17
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "activesupport"
|
3
|
+
require 'test/unit'
|
4
|
+
require "query_reviewer"
|
5
|
+
|
6
|
+
module QueryReviewer
|
7
|
+
class SqlSubQuery
|
8
|
+
include Test::Unit::Assertions
|
9
|
+
def should_warn(problem, severity = nil)
|
10
|
+
assert self.warnings.detect{|warn| warn.problem.downcase == problem.downcase &&
|
11
|
+
(!severity || warn.severity == severity)}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Test::Unit::TestCase
|
17
|
+
include QueryReviewer
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rdavila-query_reviewer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Kongregate
|
13
|
+
- David Stevenson
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-04-26 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: |
|
23
|
+
This rails plugin not only runs "EXPLAIN" before each of your select queries in development, but provides a small DIV in the rendered output of each page with the summary of query warnings that it analyzed.
|
24
|
+
|
25
|
+
email: rdavila84@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- MIT-LICENSE
|
34
|
+
- query_reviewer_defaults.yml
|
35
|
+
- Rakefile
|
36
|
+
- README
|
37
|
+
- init.rb
|
38
|
+
- lib/query_reviewer/sql_sub_query.rb
|
39
|
+
- lib/query_reviewer/array_extensions.rb
|
40
|
+
- lib/query_reviewer/views/_box_ajax.js
|
41
|
+
- lib/query_reviewer/views/_query_sql.rhtml
|
42
|
+
- lib/query_reviewer/views/_query_with_warning.rhtml
|
43
|
+
- lib/query_reviewer/views/_box_disabled.rhtml
|
44
|
+
- lib/query_reviewer/views/_explain.rhtml
|
45
|
+
- lib/query_reviewer/views/_query_trace.rhtml
|
46
|
+
- lib/query_reviewer/views/_box_includes.rhtml
|
47
|
+
- lib/query_reviewer/views/_box.rhtml
|
48
|
+
- lib/query_reviewer/views/_box_body.rhtml
|
49
|
+
- lib/query_reviewer/views/_box_header.rhtml
|
50
|
+
- lib/query_reviewer/views/_profile.rhtml
|
51
|
+
- lib/query_reviewer/views/_spectrum.rhtml
|
52
|
+
- lib/query_reviewer/views/query_review_box_helper.rb
|
53
|
+
- lib/query_reviewer/views/_warning_no_query.rhtml
|
54
|
+
- lib/query_reviewer/mysql_adapter_extensions.rb
|
55
|
+
- lib/query_reviewer/query_warning.rb
|
56
|
+
- lib/query_reviewer/controller_extensions.rb
|
57
|
+
- lib/query_reviewer/mysql_analyzer.rb
|
58
|
+
- lib/query_reviewer/sql_query.rb
|
59
|
+
- lib/query_reviewer/sql_query_collection.rb
|
60
|
+
- lib/query_reviewer.rb
|
61
|
+
- rails/init.rb
|
62
|
+
- tasks/query_reviewer_tasks.rake
|
63
|
+
- test/test_helper.rb
|
64
|
+
- test/sql_sub_query_test.rb
|
65
|
+
- test/sql_query_test.rb
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: http://github.com/dsboulder/query_reviewer
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
version: "0"
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
requirements: []
|
90
|
+
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 1.3.6
|
93
|
+
signing_key:
|
94
|
+
specification_version: 3
|
95
|
+
summary: An advanced mysql query analyzer for rails
|
96
|
+
test_files: []
|
97
|
+
|