adhoq 0.4.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +1 -1
- data/app/assets/javascripts/adhoq/current_tables.js +23 -0
- data/app/assets/javascripts/adhoq/previewer.js +52 -0
- data/app/controllers/adhoq/queries_controller.rb +1 -1
- data/app/helpers/adhoq/application_helper.rb +1 -1
- data/app/models/adhoq/execution.rb +2 -2
- data/app/models/adhoq/time_based_orders.rb +1 -1
- data/app/views/adhoq/application/_global_nav.html.erb +18 -0
- data/app/views/adhoq/current_tables/index.html.erb +53 -0
- data/app/views/adhoq/explains/create.html.erb +1 -0
- data/app/views/adhoq/explains/statement_invalid.html.erb +5 -0
- data/app/views/adhoq/previews/create.html.erb +21 -0
- data/app/views/adhoq/previews/statement_invalid.html.erb +4 -0
- data/app/views/adhoq/queries/_current_tables_leftbar.html.erb +14 -0
- data/app/views/adhoq/queries/_execution.html.erb +10 -0
- data/app/views/adhoq/queries/_form.html.erb +124 -0
- data/app/views/adhoq/queries/_queries.html.erb +16 -0
- data/app/views/adhoq/queries/_query.html.erb +67 -0
- data/app/views/adhoq/queries/edit.html.erb +13 -0
- data/app/views/adhoq/queries/index.html.erb +15 -0
- data/app/views/adhoq/queries/new.html.erb +12 -0
- data/app/views/adhoq/queries/show.html.erb +14 -0
- data/app/views/layouts/adhoq/application.html.erb +18 -0
- data/config/database.yml +25 -0
- data/lib/adhoq/engine.rb +1 -1
- data/lib/adhoq/version.rb +1 -1
- data/spec/factories/adhoq_queries.rb +9 -9
- metadata +40 -68
- data/app/assets/javascripts/adhoq/current_tables.js.coffee +0 -18
- data/app/assets/javascripts/adhoq/previewer.js.coffee +0 -34
- data/app/views/adhoq/application/_global_nav.html.slim +0 -12
- data/app/views/adhoq/current_tables/index.html.slim +0 -35
- data/app/views/adhoq/explains/create.html.slim +0 -2
- data/app/views/adhoq/explains/statement_invalid.html.slim +0 -5
- data/app/views/adhoq/previews/create.html.slim +0 -12
- data/app/views/adhoq/previews/statement_invalid.html.slim +0 -5
- data/app/views/adhoq/queries/_current_tables_leftbar.html.slim +0 -9
- data/app/views/adhoq/queries/_execution.html.slim +0 -10
- data/app/views/adhoq/queries/_form.html.slim +0 -93
- data/app/views/adhoq/queries/_queries.html.slim +0 -14
- data/app/views/adhoq/queries/_query.html.slim +0 -48
- data/app/views/adhoq/queries/edit.html.slim +0 -11
- data/app/views/adhoq/queries/index.html.slim +0 -11
- data/app/views/adhoq/queries/new.html.slim +0 -10
- data/app/views/adhoq/queries/show.html.slim +0 -11
- data/app/views/layouts/adhoq/application.html.slim +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e6a5cbb986c943cc23184441aef4ea2bf8e0ad5d0fb995d1f7a8f9e56c62b1b8
|
4
|
+
data.tar.gz: 1db27b380039a7e53455a5778cf07558af462274fa12f774d1d7ed87d3bea7ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a75e34b7025570cae4e18db014e5b20f65071335184d0f9ad194a8c2b5960916b6f796d90d316e7a0f84474bb9b70529b793528d652daf3ad300c2935156026e
|
7
|
+
data.tar.gz: 7fca78ea47976fb5ff2b45c757619284534bd09a57e6efcdf4df87f494727f0047f2d93065edb2167aaa771aa411c8f54968883fae2596dcb67518bf25a287fe
|
data/README.md
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
(function($) {
|
2
|
+
var loadCurrentTableTabOnce = function($el) {
|
3
|
+
$el.load($el.find('a.loading').attr('href'));
|
4
|
+
};
|
5
|
+
|
6
|
+
Adhoq.toggleCurrentTables = function(action, elements){
|
7
|
+
loadCurrentTableTabOnce($('#current-tables'));
|
8
|
+
|
9
|
+
var $main = $(elements.main);
|
10
|
+
var $tables = $(elements.tables);
|
11
|
+
|
12
|
+
if (action === 'show') {
|
13
|
+
$main.addClass('col-md-6').removeClass('col-md-12');
|
14
|
+
$tables.addClass('col-md-6').show();
|
15
|
+
} else {
|
16
|
+
$main.addClass('col-md-12').removeClass('col-md-6');
|
17
|
+
$tables.addClass('col-md-6').hide();
|
18
|
+
}
|
19
|
+
|
20
|
+
return true;
|
21
|
+
};
|
22
|
+
})(jQuery);
|
23
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
(function($) {
|
2
|
+
var Previewer = function(el) {
|
3
|
+
this.el = el;
|
4
|
+
}
|
5
|
+
|
6
|
+
Previewer.prototype.init = function() {
|
7
|
+
var self = this;
|
8
|
+
this.el.on('adhoq:updatePreview', function() {
|
9
|
+
self.update()
|
10
|
+
});
|
11
|
+
|
12
|
+
return this.el.on('click', function() {
|
13
|
+
self.el.trigger('adhoq:updatePreview');
|
14
|
+
return false;
|
15
|
+
});
|
16
|
+
}
|
17
|
+
|
18
|
+
Previewer.prototype.update = function() {
|
19
|
+
var self = this;
|
20
|
+
return jQuery.ajax({
|
21
|
+
type: this.el.data('method'),
|
22
|
+
url: this.el.attr('href'),
|
23
|
+
data: {query: this.source()},
|
24
|
+
complete: function(xhr) {
|
25
|
+
return self.result().html(xhr.responseText);
|
26
|
+
}
|
27
|
+
});
|
28
|
+
}
|
29
|
+
|
30
|
+
Previewer.prototype.source = function() {
|
31
|
+
return $(this.el.data('source')).val();
|
32
|
+
}
|
33
|
+
|
34
|
+
Previewer.prototype.result = function() {
|
35
|
+
return $(this.el.data('result'));
|
36
|
+
}
|
37
|
+
|
38
|
+
Adhoq.enablePreview = function($el) {
|
39
|
+
(new Previewer($el)).init()
|
40
|
+
}
|
41
|
+
|
42
|
+
Adhoq.enablePreviewKeybordShortCut = function($textarea, previewSelector) {
|
43
|
+
$textarea.on('keyup', function(ev){
|
44
|
+
if(ev.ctrlKey && (ev.keyCode === 82)) {
|
45
|
+
$(previewSelector).trigger('adhoq:updatePreview');
|
46
|
+
}
|
47
|
+
|
48
|
+
return false;
|
49
|
+
})
|
50
|
+
}
|
51
|
+
})(jQuery);
|
52
|
+
|
@@ -9,11 +9,11 @@ module Adhoq
|
|
9
9
|
|
10
10
|
def generate_report!
|
11
11
|
build_report.generate!
|
12
|
-
|
12
|
+
update(status: :success)
|
13
13
|
rescue => e
|
14
14
|
Rails.logger.error(e)
|
15
15
|
self.report = nil
|
16
|
-
|
16
|
+
update(status: :failure)
|
17
17
|
end
|
18
18
|
|
19
19
|
def name
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<nav class="navbar navbar-default" id="global-nav" role="navigation">
|
2
|
+
<div class="container-fluid">
|
3
|
+
<div class="navbar-header">
|
4
|
+
<%= link_to 'Adhoq', root_path, class: 'navbar-brand' %>
|
5
|
+
</div>
|
6
|
+
<div class="navbar-collapse collapse">
|
7
|
+
<ul class="nav navbar-nav navbar-right">
|
8
|
+
<% if main_app.respond_to?(:root_path) %>
|
9
|
+
<li>
|
10
|
+
<%= link_to main_app.root_path do %>
|
11
|
+
<i class="fa fa-arrow-circle-right fa-pad-r"></i>Main app
|
12
|
+
<% end %>
|
13
|
+
</li>
|
14
|
+
<% end %>
|
15
|
+
</ul>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</nav>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
<h3>
|
2
|
+
<i class="fa fa-database fa-pad-r" />Current tables
|
3
|
+
<small><%= "Version #{schema_version}" %></small>
|
4
|
+
<div class="pull-right">
|
5
|
+
<button class="close" data-trigger="toggleCurrentTables" role="close">
|
6
|
+
<span aria-hidden="">×</span>
|
7
|
+
</button>
|
8
|
+
</div>
|
9
|
+
</h3>
|
10
|
+
|
11
|
+
<ul class="list-unstyled tables">
|
12
|
+
<% @ar_classes.each do |ar_class| %>
|
13
|
+
<% first_record = ar_class.unscoped.order(table_order_key(ar_class)).first %>
|
14
|
+
|
15
|
+
<li class="ar_class" data-table-name="<%= ar_class.table_name %>">
|
16
|
+
<table class="table table-striped table-hover table-bordered">
|
17
|
+
<caption>
|
18
|
+
<span class="name"><%= ar_class.table_name %></span>
|
19
|
+
<% unless Adhoq.config.hide_rows_count %>
|
20
|
+
<small class="count"><%= ar_class.unscoped.count %> rows</small>
|
21
|
+
<% end %>
|
22
|
+
</caption>
|
23
|
+
<thead>
|
24
|
+
<tr>
|
25
|
+
<th class="col-sm-1 pk">PK</th>
|
26
|
+
<th class="col-sm-3 name"> Name</th>
|
27
|
+
<th class="col-sm-2 type"> Type</th>
|
28
|
+
<th class="col-sm-1 null"> Non-Null</th>
|
29
|
+
<th class="col-sm-2 limit">Limit</th>
|
30
|
+
<th class="col-sm-3 default"> Default</th>
|
31
|
+
</tr>
|
32
|
+
</thead>
|
33
|
+
<tbody>
|
34
|
+
<% ar_class.columns.each do |column| %>
|
35
|
+
<tr>
|
36
|
+
<td class="pk icon"><%= column.name == ar_class.primary_key ? icon_fa('check-circle') : '' %>
|
37
|
+
</td>
|
38
|
+
<td class="monospace"><%= column.name %>
|
39
|
+
</td>
|
40
|
+
<td><%= column.type %>
|
41
|
+
</td>
|
42
|
+
<td class="null icon"><%= column.null ? '' : icon_fa('check') %>
|
43
|
+
</td>
|
44
|
+
<td class="limit number"><%= column.limit %>
|
45
|
+
</td>
|
46
|
+
<td><%= column.default %></td>
|
47
|
+
</tr>
|
48
|
+
<% end %>
|
49
|
+
</tbody>
|
50
|
+
</table>
|
51
|
+
</li>
|
52
|
+
<% end %>
|
53
|
+
</ul>
|
@@ -0,0 +1 @@
|
|
1
|
+
<pre><%= @result %></pre>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<p class="note">
|
2
|
+
<%= @result.rows.size %> rows
|
3
|
+
</p>
|
4
|
+
<table class="table table-striped table-focus">
|
5
|
+
<thead>
|
6
|
+
<tr>
|
7
|
+
<% @result.header.each do |column| %>
|
8
|
+
<th><%= column %></th>
|
9
|
+
<% end %>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<% @result.rows.take(100).each do |row| %>
|
14
|
+
<tr>
|
15
|
+
<% row.each do |val| %>
|
16
|
+
<td><%= val %></td>
|
17
|
+
<% end %>
|
18
|
+
</tr>
|
19
|
+
<% end %>
|
20
|
+
</tbody>
|
21
|
+
</table>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div id="current-tables">
|
2
|
+
<a class="loading" href="<%= current_tables_path %>"></a>
|
3
|
+
</div>
|
4
|
+
<script>
|
5
|
+
$(function() {
|
6
|
+
|
7
|
+
$(document).on('click', '[data-trigger="toggleCurrentTables"]', function($ev) {
|
8
|
+
|
9
|
+
Adhoq.toggleCurrentTables($($ev.target).attr('role'), {main: '#main', tables: '#current-tables'});
|
10
|
+
|
11
|
+
})
|
12
|
+
|
13
|
+
});
|
14
|
+
</script>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<tr exec="">
|
2
|
+
<td class="wip"></td>
|
3
|
+
<td class="created_at"><%= exec.created_at.localtime.iso8601 %></td>
|
4
|
+
<td class="status"><%= exec.status_label %></td>
|
5
|
+
<td class="report">
|
6
|
+
<% if exec.success? %>
|
7
|
+
<%= link_to(query_execution_path(query, exec, format: exec.report_format), class: 'btn btn-sm btn-default') do %>
|
8
|
+
<i class="fa fa-download fa-pad-r"></i><%= exec.report_format %>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
@@ -0,0 +1,124 @@
|
|
1
|
+
<%= form_for query, html: {class: 'form query-form', role: 'form'} do |f| %>
|
2
|
+
<div class="page-header">
|
3
|
+
<h1>
|
4
|
+
<%= f.label :query, title, class: 'control-label' %>
|
5
|
+
<div class="pull-right">
|
6
|
+
<a href="#" class="btn btn-default btn-sm" data-trigger="toggleCurrentTables" role="show">
|
7
|
+
<i class="fa fa-database fa-pad-r"></i> Show tables
|
8
|
+
</a>
|
9
|
+
</div>
|
10
|
+
</h1>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<div class="form-group">
|
14
|
+
<%= f.text_area :query, class: 'form-control', rows: 15, required: true %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<div class="modal fade" id="nameAndDesc" role="dialog">
|
18
|
+
<div class="modal-dialog">
|
19
|
+
<div class="modal-content">
|
20
|
+
<div class="modal-header">
|
21
|
+
<button class="close" data-dismiss="modal" aria-label="close" />
|
22
|
+
<button class="close" type="button" data-dismiss="modal" aria-label="close">
|
23
|
+
<span aria-hidden="true">×</span>
|
24
|
+
</button>
|
25
|
+
|
26
|
+
<h4>Add name and description to query</h4>
|
27
|
+
</div>
|
28
|
+
<div class="modal-body">
|
29
|
+
<div class="form-horizontal">
|
30
|
+
<div class="form-group">
|
31
|
+
<%= f.label :name, class: 'control-label col-sm-2' %>
|
32
|
+
<div class="col-sm-8">
|
33
|
+
<%= f.text_field :name, class: 'form-control', required: true %>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
<div class="form-group">
|
37
|
+
<%= f.label :description, class: 'control-label col-sm-2' %>
|
38
|
+
<div class="col-sm-8">
|
39
|
+
<%= f.text_area :description, class: 'form-control' %>
|
40
|
+
</div>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
<div class="modal-footer">
|
45
|
+
<button class="btn btn-primary center-block">
|
46
|
+
<i class="fa fa-floppy-o fa-pad-r"></i>Save
|
47
|
+
</button>
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
<div class="actions">
|
54
|
+
<% if query.persisted? %>
|
55
|
+
<%= link_to query do %>
|
56
|
+
<i class="fa fa-arrow-left fa-pad-r"></i>Cancel
|
57
|
+
<% end %>
|
58
|
+
<% else %>
|
59
|
+
<%= link_to :queries do %>
|
60
|
+
<i class="fa fa-arrow-left fa-pad-r"></i>Back to Index
|
61
|
+
<% end %>
|
62
|
+
<% end %>
|
63
|
+
|
64
|
+
<div class="pull-right">
|
65
|
+
<%= link_to '#nameAndDesc', class: 'btn btn-default btn-sm', data: {toggle: 'modal', target: '#nameAndDesc'} do %>
|
66
|
+
<i class="fa fa-floppy-o fa-pad-r"></i>Save as...
|
67
|
+
<% end %>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
|
71
|
+
<% end %>
|
72
|
+
|
73
|
+
<ul class="nav nav-tabs" role="tablist">
|
74
|
+
<li class="active">
|
75
|
+
<a data-toggle="tab" href="#preview" role="tab">
|
76
|
+
<i class="fa fa-eye fa-pad-r"></i>Preview
|
77
|
+
</a>
|
78
|
+
</li>
|
79
|
+
<li>
|
80
|
+
<a data-toggle="tab" href="#explain" role="tab">
|
81
|
+
<i class="fa fa-info fa-pad-r"></i>Explain
|
82
|
+
</a>
|
83
|
+
</li>
|
84
|
+
</ul>
|
85
|
+
|
86
|
+
<div class="tab-content" id="previews">
|
87
|
+
<div class="tab-pane active" id="preview">
|
88
|
+
<h3>Query preview
|
89
|
+
<small>
|
90
|
+
<%= link_to preview_path, class: 'js-preview-button', data: {source: '#query_query', result: '.js-preview-result', remote: true, method: 'POST'} do %>
|
91
|
+
<i class="fa fa-refresh fa-pad-r" data-title="Refresh preview"></i> Refresh
|
92
|
+
<% end %>
|
93
|
+
</small>
|
94
|
+
</h3>
|
95
|
+
<div class="js-preview-result">
|
96
|
+
<div class="alert alert-info">Preview is shown here</div>
|
97
|
+
</div>
|
98
|
+
</div>
|
99
|
+
<div class="tab-pane" id="explain">
|
100
|
+
<h3>Query explain
|
101
|
+
<small>
|
102
|
+
<%= link_to explain_path, class: 'js-explain-button', data: {source: '#query_query', result: '.js-explain-result', remote: true, method: 'POST'} do %>
|
103
|
+
<i class="fa fa-refresh fa-pad-r" data-title="Refresh explain"></i> Refresh
|
104
|
+
<% end %>
|
105
|
+
</small>
|
106
|
+
</h3>
|
107
|
+
<div class="js-explain-result">
|
108
|
+
<div class="alert alert-info">Explain result is shown here</div>
|
109
|
+
</div>
|
110
|
+
</div>
|
111
|
+
</div>
|
112
|
+
<script>
|
113
|
+
$(function() {
|
114
|
+
|
115
|
+
Adhoq.enablePreview($('#preview a.js-preview-button'));
|
116
|
+
|
117
|
+
Adhoq.enablePreview($('#explain a.js-explain-button'));
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
Adhoq.enablePreviewKeybordShortCut($('#query_query'), '#previews .tab-pane.active a:has(".fa-refresh")')
|
122
|
+
|
123
|
+
});
|
124
|
+
</script>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% highlight ||= nil %>
|
2
|
+
<section>
|
3
|
+
<%= link_to :root, class: 'btn btn-default new-query btn-sm center-block' do %>
|
4
|
+
<i class="fa fa-plus-square fa-pad-r"></i>New query
|
5
|
+
<% end %>
|
6
|
+
<ol class="queries-index list-unstyled">
|
7
|
+
<% queries.each do |query| %>
|
8
|
+
<li class="panel <%= query == highlight ? 'panel-success' : 'panel-default' %>">
|
9
|
+
<div class="panel-heading">
|
10
|
+
<h2><%= link_to query.name, query_path(query) %></h2>
|
11
|
+
</div>
|
12
|
+
<p class="panel-body description"><%= query.description %></p>
|
13
|
+
</li>
|
14
|
+
<% end %>
|
15
|
+
</ol>
|
16
|
+
</section>
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<section class="query">
|
2
|
+
<div class="page-header">
|
3
|
+
<h1>
|
4
|
+
<%= query.name %>
|
5
|
+
<div class="pull-right">
|
6
|
+
<%= link_to [:edit, query], class: 'btn btn-default btn-sm' do %>
|
7
|
+
<i class="fa fa-pencil fa-pad-r" ></i> Edit
|
8
|
+
<% end %>
|
9
|
+
</div>
|
10
|
+
<div class="pull-right">
|
11
|
+
<%= link_to 'Delete', query, class: 'btn btn-default btn-sm', method: :delete, data: { confirm: 'Are you sure?' } %>
|
12
|
+
</div>
|
13
|
+
<div class="clearfix" />
|
14
|
+
<small><%= "Updated at #{l(query.updated_at, format: :short)}" %></small>
|
15
|
+
</h1>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<p class="description"><%= query.description %></p>
|
19
|
+
<style type="text/css">
|
20
|
+
<%= Rouge::Themes::Github.render(scope: '.highlight') %>
|
21
|
+
</style>
|
22
|
+
|
23
|
+
<%= raw query.query_with_highlight %>
|
24
|
+
|
25
|
+
<section class="new-execution">
|
26
|
+
<h2>Create report</h2>
|
27
|
+
<%= form_for [query, query.executions.build], html: {role: 'form'} do |f| %>
|
28
|
+
<div class="form-inline form-group report_format">
|
29
|
+
<%= f.label :report_format %>
|
30
|
+
<%= f.select :report_format, f.object.supported_formats, {}, class: 'form-control' %>
|
31
|
+
<% if query.parameters.present? %>
|
32
|
+
<h4>Query parameters</h4>
|
33
|
+
<div class="form-group query_parameters">
|
34
|
+
<% query.parameters.each do |param_name| %>
|
35
|
+
<div class="form-inline query_parameter">
|
36
|
+
<%= label_tag "parameters_#{param_name}", "#{param_name}" %>
|
37
|
+
<%= query_parameter_field(param_name) %>
|
38
|
+
</div>
|
39
|
+
<% end %>
|
40
|
+
</div>
|
41
|
+
<% end %>
|
42
|
+
<div class="form-group">
|
43
|
+
<%= f.submit 'Create report', class: 'btn btn-default' %>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
<% end %>
|
47
|
+
</section>
|
48
|
+
<section class="past-executions">
|
49
|
+
<h2>Reports</h2>
|
50
|
+
<table class="executions table table-striped table-hover">
|
51
|
+
<thead>
|
52
|
+
<tr>
|
53
|
+
<th class="wip"> </th>
|
54
|
+
<th class="created_at"><%= human(Adhoq::Execution, :created_at) %></th>
|
55
|
+
<th class="status"><%= human(Adhoq::Execution, :status) %></th>
|
56
|
+
<th class="report"></th>
|
57
|
+
</tr>
|
58
|
+
</thead>
|
59
|
+
<tbody>
|
60
|
+
<% query.executions.recent_first.preload(:report).each do |exec| %>
|
61
|
+
<% next if exec.report.try(:on_the_fly?) %>
|
62
|
+
<%= render 'execution', query: query, exec: exec %>
|
63
|
+
<% end %>
|
64
|
+
</tbody>
|
65
|
+
</table>
|
66
|
+
</section>
|
67
|
+
</section>
|