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.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +1 -1
  3. data/app/assets/javascripts/adhoq/current_tables.js +23 -0
  4. data/app/assets/javascripts/adhoq/previewer.js +52 -0
  5. data/app/controllers/adhoq/queries_controller.rb +1 -1
  6. data/app/helpers/adhoq/application_helper.rb +1 -1
  7. data/app/models/adhoq/execution.rb +2 -2
  8. data/app/models/adhoq/time_based_orders.rb +1 -1
  9. data/app/views/adhoq/application/_global_nav.html.erb +18 -0
  10. data/app/views/adhoq/current_tables/index.html.erb +53 -0
  11. data/app/views/adhoq/explains/create.html.erb +1 -0
  12. data/app/views/adhoq/explains/statement_invalid.html.erb +5 -0
  13. data/app/views/adhoq/previews/create.html.erb +21 -0
  14. data/app/views/adhoq/previews/statement_invalid.html.erb +4 -0
  15. data/app/views/adhoq/queries/_current_tables_leftbar.html.erb +14 -0
  16. data/app/views/adhoq/queries/_execution.html.erb +10 -0
  17. data/app/views/adhoq/queries/_form.html.erb +124 -0
  18. data/app/views/adhoq/queries/_queries.html.erb +16 -0
  19. data/app/views/adhoq/queries/_query.html.erb +67 -0
  20. data/app/views/adhoq/queries/edit.html.erb +13 -0
  21. data/app/views/adhoq/queries/index.html.erb +15 -0
  22. data/app/views/adhoq/queries/new.html.erb +12 -0
  23. data/app/views/adhoq/queries/show.html.erb +14 -0
  24. data/app/views/layouts/adhoq/application.html.erb +18 -0
  25. data/config/database.yml +25 -0
  26. data/lib/adhoq/engine.rb +1 -1
  27. data/lib/adhoq/version.rb +1 -1
  28. data/spec/factories/adhoq_queries.rb +9 -9
  29. metadata +40 -68
  30. data/app/assets/javascripts/adhoq/current_tables.js.coffee +0 -18
  31. data/app/assets/javascripts/adhoq/previewer.js.coffee +0 -34
  32. data/app/views/adhoq/application/_global_nav.html.slim +0 -12
  33. data/app/views/adhoq/current_tables/index.html.slim +0 -35
  34. data/app/views/adhoq/explains/create.html.slim +0 -2
  35. data/app/views/adhoq/explains/statement_invalid.html.slim +0 -5
  36. data/app/views/adhoq/previews/create.html.slim +0 -12
  37. data/app/views/adhoq/previews/statement_invalid.html.slim +0 -5
  38. data/app/views/adhoq/queries/_current_tables_leftbar.html.slim +0 -9
  39. data/app/views/adhoq/queries/_execution.html.slim +0 -10
  40. data/app/views/adhoq/queries/_form.html.slim +0 -93
  41. data/app/views/adhoq/queries/_queries.html.slim +0 -14
  42. data/app/views/adhoq/queries/_query.html.slim +0 -48
  43. data/app/views/adhoq/queries/edit.html.slim +0 -11
  44. data/app/views/adhoq/queries/index.html.slim +0 -11
  45. data/app/views/adhoq/queries/new.html.slim +0 -10
  46. data/app/views/adhoq/queries/show.html.slim +0 -11
  47. data/app/views/layouts/adhoq/application.html.slim +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 55ebbfcb4634de6d7ff7b565a620aea07cdb739c
4
- data.tar.gz: 4a46756086ac03ff5f8564797fff26522fb0f4a2
2
+ SHA256:
3
+ metadata.gz: e6a5cbb986c943cc23184441aef4ea2bf8e0ad5d0fb995d1f7a8f9e56c62b1b8
4
+ data.tar.gz: 1db27b380039a7e53455a5778cf07558af462274fa12f774d1d7ed87d3bea7ac
5
5
  SHA512:
6
- metadata.gz: 19c49904e45e9eedf169134bc6564448e0974af82a61862bc8fffc33c3bd1a921cb976acf7c962e34b963b38ec99ad06f21b0d0c07ec6dd3bed30856901cec1c
7
- data.tar.gz: cae892aac89db0af6e29568fac5aac68c2adab131315fa87fdf38dd8a002e9397c8b85dd2864f4b09c0fb745799597d0a313c0c56e3e6288662d94977b6508b7
6
+ metadata.gz: a75e34b7025570cae4e18db014e5b20f65071335184d0f9ad194a8c2b5960916b6f796d90d316e7a0f84474bb9b70529b793528d652daf3ad300c2935156026e
7
+ data.tar.gz: 7fca78ea47976fb5ff2b45c757619284534bd09a57e6efcdf4df87f494727f0047f2d93065edb2167aaa771aa411c8f54968883fae2596dcb67518bf25a287fe
data/README.md CHANGED
@@ -12,7 +12,7 @@ Rails engine to generate instant reports from adhoc SQL query.
12
12
  - .json
13
13
  - .xlsx
14
14
  - Persist generated report as local file or in AWS S3
15
- - Rails 4.x
15
+ - over Rails 5.1.X
16
16
  - Nice administration console with rails engine
17
17
 
18
18
  ### Future planning
@@ -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
+
@@ -24,7 +24,7 @@ module Adhoq
24
24
 
25
25
  def update
26
26
  @query = Adhoq::Query.find(params[:id])
27
- @query.update_attributes!(query_attributes)
27
+ @query.update!(query_attributes)
28
28
 
29
29
  redirect_to @query
30
30
  end
@@ -24,7 +24,7 @@ module Adhoq
24
24
  end
25
25
 
26
26
  def table_order_key(ar_class)
27
- ar_class.primary_key || ar_class.columns.first.name
27
+ (ar_class.primary_key || ar_class.columns.first.name).to_sym
28
28
  end
29
29
 
30
30
  def query_parameter_field(name)
@@ -9,11 +9,11 @@ module Adhoq
9
9
 
10
10
  def generate_report!
11
11
  build_report.generate!
12
- update_attributes(status: :success)
12
+ update(status: :success)
13
13
  rescue => e
14
14
  Rails.logger.error(e)
15
15
  self.report = nil
16
- update_attributes(status: :failure)
16
+ update(status: :failure)
17
17
  end
18
18
 
19
19
  def name
@@ -3,7 +3,7 @@ module Adhoq
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- scope :recent_first, -> { order("#{quoted_table_name}.updated_at DESC") }
6
+ scope :recent_first, -> { order(arel_table[:updated_at].desc) }
7
7
  end
8
8
  end
9
9
  end
@@ -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="">&times;</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,5 @@
1
+ <p class="statement-invalid alert alert-danger">
2
+ <strong><%= @statement_invalid.cause.class %>
3
+ </strong><br />
4
+ <%= @statement_invalid.cause.message %>
5
+ </p>
@@ -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,4 @@
1
+ <p class="statement-invalid alert alert-danger">
2
+ <strong><%= @statement_invalid.cause.class %></strong><br />
3
+ <%= @statement_invalid.cause.message %>
4
+ </p>
@@ -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">&times;</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">&nbsp;</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>