adhoq 0.4.0 → 1.0.2
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.
- 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>
|