adhoq 0.0.2 → 0.0.3
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 +4 -4
- data/README.md +45 -12
- data/app/assets/javascripts/adhoq/application.js +1 -0
- data/app/assets/javascripts/adhoq/current_tables.js.coffee +4 -0
- data/app/assets/stylesheets/adhoq/adhoq.css.sass +44 -0
- data/app/assets/stylesheets/adhoq/bootstrap.scss +1 -1
- data/app/controllers/adhoq/authorization_methods.rb +1 -1
- data/app/controllers/adhoq/current_tables_controller.rb +20 -0
- data/app/controllers/adhoq/executions_controller.rb +2 -2
- data/app/helpers/adhoq/application_helper.rb +13 -0
- data/app/models/adhoq/execution.rb +1 -1
- data/app/models/adhoq/report.rb +10 -17
- data/app/views/adhoq/application/_global_nav.html.slim +1 -0
- data/app/views/adhoq/current_tables/index.html.slim +32 -0
- data/app/views/adhoq/queries/_form.html.slim +29 -9
- data/app/views/adhoq/queries/_query.html.slim +1 -1
- data/config/routes.rb +2 -1
- data/lib/adhoq.rb +7 -6
- data/lib/adhoq/adhoc_execution.rb +11 -0
- data/lib/adhoq/executor.rb +12 -1
- data/lib/adhoq/global_variable.rb +8 -5
- data/lib/adhoq/reporter.rb +14 -0
- data/lib/adhoq/storage.rb +12 -1
- data/lib/adhoq/storage/fog_storage.rb +22 -0
- data/lib/adhoq/storage/local_file.rb +10 -29
- data/lib/adhoq/storage/s3.rb +24 -0
- data/lib/adhoq/version.rb +1 -1
- data/spec/adhoq/executor_spec.rb +13 -0
- data/spec/adhoq/global_variable_spec.rb +37 -0
- data/spec/adhoq/reporter/xlsx_spec.rb +18 -0
- data/spec/adhoq/storage_spec.rb +12 -2
- data/spec/spec_helper.rb +29 -2
- data/spec/support/codeclimate_reporter.rb +4 -0
- data/spec/support/feature_spec_helper.rb +5 -0
- data/spec/support/have_values_in_xlsx_sheet_matcher.rb +9 -3
- metadata +97 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a9fac13cfa25151dce3d5c579c39ba8098f07b6f
|
|
4
|
+
data.tar.gz: 23f822e233cc7977a2461dbe681a30d2426fffd5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6d1804945abba5952f20f671f68e5fab9141d474dfdcc70aab8a6317cd3c975296e244b6d480a27a2e19066ec2c56eeaadde874ddd3617281275b23c08de6bb
|
|
7
|
+
data.tar.gz: 25dac12d074dff4dead41cb23271447737f237103aa494f4148b509b0a6f8cb30be2c1bd3aff9e63fe83763836c744be5249e48422d78d290afdd26685473904
|
data/README.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
Adhoq [](https://travis-ci.org/esminc/adhoq) [](https://codeclimate.com/github/esminc/adhoq)
|
|
2
|
+
====
|
|
2
3
|
|
|
3
4
|
Rails engine to generate instant reports from adhoc SQL query.
|
|
4
5
|
|
|
@@ -6,16 +7,17 @@ Rails engine to generate instant reports from adhoc SQL query.
|
|
|
6
7
|
|
|
7
8
|
## Features
|
|
8
9
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
10
|
+
- Export ad-hoc SQL result to .xlsx file
|
|
11
|
+
- Persist generated report as local file or in AWS S3
|
|
12
|
+
- Rails 4.x & 3.2 support
|
|
13
|
+
- Nice administration console with rails engine
|
|
14
|
+
|
|
15
|
+
### Future planning
|
|
16
|
+
|
|
11
17
|
- Export reports in some formats:
|
|
12
|
-
- [x] .xlsx
|
|
13
18
|
- [ ] .csv
|
|
14
19
|
- [ ] .json
|
|
15
|
-
-
|
|
16
|
-
- [x] as local file
|
|
17
|
-
- [ ] S3 (via `Fog::Storage`)
|
|
18
|
-
- [ ] In application export function helper
|
|
20
|
+
- [ ] Label data substitution
|
|
19
21
|
|
|
20
22
|
## Installation
|
|
21
23
|
|
|
@@ -58,22 +60,53 @@ Edit initialization file in `config/initializer/adhoq.rb`
|
|
|
58
60
|
|
|
59
61
|
```ruby
|
|
60
62
|
Adhoq.configure do |config|
|
|
61
|
-
config.storage = [:local_file, Rails.root + '
|
|
63
|
+
config.storage = [:local_file, Rails.root + './path/to/store/report/files']
|
|
62
64
|
config.authorization = ->(controller) { controller.signed_in? }
|
|
63
65
|
end
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-
See configuration example in [dummy app](https://github.com/esminc/adhoq/
|
|
68
|
+
See configuration example in [dummy app](https://github.com/esminc/adhoq/blob/master/spec/dummy/config/initializers/adhoq.rb).
|
|
67
69
|
|
|
68
70
|
Then restart server and try it out.
|
|
69
71
|
|
|
70
72
|
### As Plain old library (application export helper)
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
Adhoq also provides report generation from SQL string, not from mounted rails engine.
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
execution = Adhoq::AdhocExecution.new(
|
|
78
|
+
'xlsx',
|
|
79
|
+
'SELECT "hello" AS name ,"English greeting message" AS description'
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
Adhoq::Reporter.generate(execution) #=> report data
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Persistence is also available without engine via `Adhoq::Storage::SomeClass#store`.
|
|
86
|
+
Below is example that generating report and persist to in Rails application report method.
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
execution = Adhoq::AdhocExecution.new(
|
|
90
|
+
'xlsx',
|
|
91
|
+
'SELECT "hello" AS name ,"English greeting message" AS description'
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
storage = Storage::S3.new(
|
|
95
|
+
'my-adhoq-bucket',
|
|
96
|
+
aws_access_key_id: 'key_id',
|
|
97
|
+
aws_secret_access_key: 'access_key'
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# generate report and store it to S3, returns `key` to get report data
|
|
101
|
+
key = storage.store('.xlsx') { Adhoq::Reporter.generate(execution) }
|
|
102
|
+
|
|
103
|
+
...
|
|
104
|
+
storage.get(key) #=> report data
|
|
105
|
+
```
|
|
73
106
|
|
|
74
107
|
## Contributing
|
|
75
108
|
|
|
76
|
-
1. Fork it ( https://github.com/
|
|
109
|
+
1. Fork it ( https://github.com/esminc/adhoq/fork )
|
|
77
110
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
78
111
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
79
112
|
4. Push to the branch (`git push origin my-new-feature`)
|
|
@@ -55,3 +55,47 @@ form.query-form
|
|
|
55
55
|
|
|
56
56
|
.fa-pad-l
|
|
57
57
|
padding-left: $short-span / 2
|
|
58
|
+
|
|
59
|
+
#current-tables
|
|
60
|
+
font-size: $font-size-base * 0.9
|
|
61
|
+
|
|
62
|
+
table
|
|
63
|
+
width: 800px
|
|
64
|
+
|
|
65
|
+
caption
|
|
66
|
+
text-align: left
|
|
67
|
+
margin-bottom: $short-span
|
|
68
|
+
font-size: $font-size-base * 1.5
|
|
69
|
+
|
|
70
|
+
span.name
|
|
71
|
+
font-family: monospace
|
|
72
|
+
small.count
|
|
73
|
+
font-size: $font-size-base * 1
|
|
74
|
+
color: gray
|
|
75
|
+
margin-left: $font-size-base
|
|
76
|
+
|
|
77
|
+
th.pk, td.pk
|
|
78
|
+
width: $font-size-base * 1.5
|
|
79
|
+
th, td.icon
|
|
80
|
+
text-align: center
|
|
81
|
+
th.number, td.number
|
|
82
|
+
text-align: right
|
|
83
|
+
th.monospace, td.monospace
|
|
84
|
+
font-family: monospace
|
|
85
|
+
th.data
|
|
86
|
+
width: $font-size-base * 10
|
|
87
|
+
|
|
88
|
+
.tab-content
|
|
89
|
+
margin-top: $font-size-base
|
|
90
|
+
padding-left: 1em
|
|
91
|
+
padding-right: 1em
|
|
92
|
+
|
|
93
|
+
max-height: 600px
|
|
94
|
+
overflow: scroll
|
|
95
|
+
|
|
96
|
+
.tab-pane > h3
|
|
97
|
+
font-size: $font-size-base * 1.5
|
|
98
|
+
|
|
99
|
+
small
|
|
100
|
+
font-size: $font-size-base
|
|
101
|
+
margin-left: $font-size-base
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Adhoq
|
|
2
|
+
class CurrentTablesController < Adhoq::ApplicationController
|
|
3
|
+
before_filter :eager_load_models
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
@ar_classes = ActiveRecord::Base.subclasses.
|
|
7
|
+
reject {|klass| klass.name == 'ActiveRecord::SchemaMigration' }.
|
|
8
|
+
sort_by(&:name)
|
|
9
|
+
|
|
10
|
+
render layout: false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def eager_load_models
|
|
16
|
+
return unless Rails.env.development?
|
|
17
|
+
[Rails.application, Adhoq::Engine].each(&:eager_load!)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module Adhoq
|
|
2
|
-
class ExecutionsController < ApplicationController
|
|
2
|
+
class ExecutionsController < Adhoq::ApplicationController
|
|
3
3
|
def show
|
|
4
4
|
@execution = current_query.executions.where(id: params[:id], report_format: params[:format]).first!
|
|
5
5
|
|
|
@@ -19,7 +19,7 @@ module Adhoq
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def respond_report(report)
|
|
22
|
-
send_data report.data
|
|
22
|
+
send_data report.data, type: report.mime_type, filename: report.name, disposition: 'attachment'
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -7,5 +7,18 @@ module Adhoq
|
|
|
7
7
|
klass.model_name.humanize
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
|
+
|
|
11
|
+
def icon_fa(name, additional_classes = [])
|
|
12
|
+
tag('i', class: ['fa', "fa-#{name}", *additional_classes])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def schema_version
|
|
16
|
+
if defined?(ActiveRecord::SchemaMigration)
|
|
17
|
+
ActiveRecord::SchemaMigration.maximum(:version)
|
|
18
|
+
else
|
|
19
|
+
result = Adhoq::Executor.select("SELECT MAX(version) AS current_version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
|
|
20
|
+
result.rows.first
|
|
21
|
+
end
|
|
22
|
+
end
|
|
10
23
|
end
|
|
11
24
|
end
|
data/app/models/adhoq/report.rb
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
module Adhoq
|
|
2
2
|
class Report < ActiveRecord::Base
|
|
3
|
-
BUFSIZE = 10.kilobytes.to_i
|
|
4
|
-
|
|
5
3
|
belongs_to :execution
|
|
6
4
|
|
|
7
|
-
delegate :name,
|
|
8
|
-
delegate :mime_type, to: :reporter
|
|
5
|
+
delegate :name, to: 'execution'
|
|
9
6
|
|
|
10
7
|
def generate!(storage = Adhoq.current_storage)
|
|
11
8
|
self.identifier = generate_and_persist_report!(storage)
|
|
@@ -15,28 +12,24 @@ module Adhoq
|
|
|
15
12
|
save!
|
|
16
13
|
end
|
|
17
14
|
|
|
18
|
-
def
|
|
19
|
-
|
|
15
|
+
def available?
|
|
16
|
+
identifier.present? && (storage == Adhoq.current_storage.identifier)
|
|
20
17
|
end
|
|
21
18
|
|
|
22
19
|
def data(storage = Adhoq.current_storage)
|
|
23
20
|
storage.get(identifier)
|
|
24
21
|
end
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def reporter
|
|
29
|
-
{'xlsx' => Adhoq::Reporter::Xlsx}[execution.report_format]
|
|
23
|
+
def mime_type
|
|
24
|
+
Adhoq::Reporter.lookup(execution.report_format).mime_type
|
|
30
25
|
end
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
storage.store(".#{execution.report_format}") do |file, *|
|
|
34
|
-
executor = Executor.new(execution.raw_sql)
|
|
27
|
+
private
|
|
35
28
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
def generate_and_persist_report!(storage)
|
|
30
|
+
storage.store(".#{execution.report_format}") {
|
|
31
|
+
Adhoq::Reporter.generate(execution)
|
|
32
|
+
}
|
|
40
33
|
end
|
|
41
34
|
end
|
|
42
35
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
h3
|
|
2
|
+
| Current database schema
|
|
3
|
+
small= "Version #{schema_version}"
|
|
4
|
+
|
|
5
|
+
ul.list-unstyled.tables
|
|
6
|
+
- @ar_classes.each do |ar_class|
|
|
7
|
+
- first_record = ar_class.unscoped.order(:id).first
|
|
8
|
+
|
|
9
|
+
li.ar_class data-table-name=ar_class.table_name
|
|
10
|
+
table.table.table-striped.table-hover.table-bordered
|
|
11
|
+
caption
|
|
12
|
+
span.name= ar_class.table_name
|
|
13
|
+
small.count #{ar_class.unscoped.count} rows
|
|
14
|
+
thead
|
|
15
|
+
tr
|
|
16
|
+
th.col-sm-1.pk PK
|
|
17
|
+
th.col-sm-2.name Name
|
|
18
|
+
th.col-sm-1.type Type
|
|
19
|
+
th.col-sm-1.null Non-Null
|
|
20
|
+
th.col-sm-1.limit Limit
|
|
21
|
+
th.col-sm-2.default Default
|
|
22
|
+
th.col-sm-4.data unscoped.first
|
|
23
|
+
tbody
|
|
24
|
+
- ar_class.columns.each do |column|
|
|
25
|
+
tr
|
|
26
|
+
td.pk.icon= column.primary ? icon_fa('check-circle') : ''
|
|
27
|
+
td.monospace= column.name
|
|
28
|
+
td= column.type
|
|
29
|
+
td.null.icon= column.null ? '' : icon_fa('check')
|
|
30
|
+
td.limit.number= column.limit
|
|
31
|
+
td= column.default
|
|
32
|
+
td.monospace= first_record.try {|r| truncate(r.read_attribute_before_type_cast(column.name).to_s, length: 50) }
|
|
@@ -24,15 +24,35 @@
|
|
|
24
24
|
.col-sm-8
|
|
25
25
|
= f.text_area :query, class: 'form-control', rows: 10, required: true
|
|
26
26
|
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
ul.nav.nav-tabs[role='tablist']
|
|
28
|
+
li.active
|
|
29
|
+
a[role='tab' data-toggle='tab' href='#preview' ]
|
|
30
|
+
i.fa.fa-eye.fa-pad-r
|
|
31
|
+
| Preview
|
|
32
|
+
li
|
|
33
|
+
a[role='tab' data-toggle='tab' href='#current-tables']
|
|
34
|
+
i.fa.fa-database.fa-pad-r
|
|
35
|
+
| Tables
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
.tab-content
|
|
38
|
+
#preview.tab-pane.active
|
|
39
|
+
h3
|
|
40
|
+
| Query preview
|
|
41
|
+
small
|
|
42
|
+
= link_to preview_path, class: 'js-preview-button', data: {source: '#query_query', result: '.js-preview-result', remote: true, method: 'POST'} do
|
|
43
|
+
i.fa.fa-refresh.fa-pad-r[data-title='Refresh preview']
|
|
44
|
+
| Reflesh
|
|
45
|
+
|
|
46
|
+
.js-preview-result
|
|
47
|
+
.alert.alert-info Preview is shown here
|
|
48
|
+
|
|
49
|
+
#current-tables.tab-pane
|
|
50
|
+
a.loading[href=current_tables_path]
|
|
36
51
|
|
|
37
52
|
javascript:
|
|
38
|
-
$(function() {
|
|
53
|
+
$(function() {
|
|
54
|
+
Adhoq.enablePreview($('#preview a.js-preview-button'));
|
|
55
|
+
|
|
56
|
+
$('a[data-toggle="tab"]').on('show.bs.tab', function(ev) { Adhoq.loadCurrentTableTabOnce($(ev.target)) });
|
|
57
|
+
});
|
|
58
|
+
|
|
@@ -38,6 +38,6 @@ section.query
|
|
|
38
38
|
span.label[class=(exec.success? ? 'label-success' : 'label-danger')]= exec.status_label
|
|
39
39
|
td.report
|
|
40
40
|
- if exec.success?
|
|
41
|
-
= link_to(
|
|
41
|
+
= link_to(adhoq.query_execution_path(query, exec, format: exec.report_format), class: 'btn btn-sm btn-default') do
|
|
42
42
|
i.fa.fa-download.fa-pad-r
|
|
43
43
|
= exec.report_format
|
data/config/routes.rb
CHANGED
data/lib/adhoq.rb
CHANGED
|
@@ -2,12 +2,13 @@ require 'adhoq/engine'
|
|
|
2
2
|
require 'adhoq/global_variable'
|
|
3
3
|
|
|
4
4
|
module Adhoq
|
|
5
|
-
autoload '
|
|
6
|
-
autoload '
|
|
7
|
-
autoload '
|
|
8
|
-
autoload '
|
|
9
|
-
autoload '
|
|
10
|
-
autoload '
|
|
5
|
+
autoload 'AdhocExecution', 'adhoq/adhoc_execution'
|
|
6
|
+
autoload 'Configuration', 'adhoq/configuration'
|
|
7
|
+
autoload 'Error', 'adhoq/error'
|
|
8
|
+
autoload 'Executor', 'adhoq/executor'
|
|
9
|
+
autoload 'Reporter', 'adhoq/reporter'
|
|
10
|
+
autoload 'Result', 'adhoq/result'
|
|
11
|
+
autoload 'Storage', 'adhoq/storage'
|
|
11
12
|
|
|
12
13
|
extend Adhoq::GlobalVariable
|
|
13
14
|
end
|
data/lib/adhoq/executor.rb
CHANGED
|
@@ -2,12 +2,23 @@ module Adhoq
|
|
|
2
2
|
class Executor
|
|
3
3
|
class << self
|
|
4
4
|
def select(query)
|
|
5
|
-
|
|
5
|
+
with_sandbox do
|
|
6
|
+
current_connection.exec_query(query)
|
|
7
|
+
end
|
|
6
8
|
end
|
|
7
9
|
|
|
8
10
|
def current_connection
|
|
9
11
|
ActiveRecord::Base.connection
|
|
10
12
|
end
|
|
13
|
+
|
|
14
|
+
def with_sandbox
|
|
15
|
+
result = nil
|
|
16
|
+
ActiveRecord::Base.transaction do
|
|
17
|
+
result = yield
|
|
18
|
+
raise ActiveRecord::Rollback
|
|
19
|
+
end
|
|
20
|
+
result
|
|
21
|
+
end
|
|
11
22
|
end
|
|
12
23
|
|
|
13
24
|
def initialize(query)
|
|
@@ -22,13 +22,16 @@ module Adhoq
|
|
|
22
22
|
|
|
23
23
|
private
|
|
24
24
|
|
|
25
|
-
# TODO Implement S3
|
|
26
25
|
def setup_storage(type, *args)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
klass =
|
|
27
|
+
case type
|
|
28
|
+
when :local_file then Adhoq::Storage::LocalFile
|
|
29
|
+
when :s3 then Adhoq::Storage::S3
|
|
30
|
+
else
|
|
31
|
+
raise NotImplementedError
|
|
32
|
+
end
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
klass.new(*args)
|
|
32
35
|
end
|
|
33
36
|
end
|
|
34
37
|
end
|
data/lib/adhoq/reporter.rb
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
module Adhoq
|
|
2
2
|
module Reporter
|
|
3
3
|
autoload 'Xlsx', 'adhoq/reporter/xlsx'
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
def generate(execution)
|
|
7
|
+
executor = Executor.new(execution.raw_sql)
|
|
8
|
+
reporter = lookup(execution.report_format).new(executor.execute)
|
|
9
|
+
|
|
10
|
+
reporter.build_report
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def lookup(format)
|
|
14
|
+
@map ||= {'xlsx' => Adhoq::Reporter::Xlsx}
|
|
15
|
+
@map[format]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
4
18
|
end
|
|
5
19
|
end
|
data/lib/adhoq/storage.rb
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
module Adhoq
|
|
2
2
|
module Storage
|
|
3
|
-
autoload '
|
|
3
|
+
autoload 'FogStorage', 'adhoq/storage/fog_storage'
|
|
4
|
+
autoload 'LocalFile', 'adhoq/storage/local_file'
|
|
5
|
+
autoload 'S3', 'adhoq/storage/s3'
|
|
6
|
+
|
|
7
|
+
def with_new_identifier(suffix = nil, seed = Time.now)
|
|
8
|
+
dirname, fname_seed = ['%Y-%m-%d', '%H%M%S.%L'].map {|f| seed.strftime(f) }
|
|
9
|
+
|
|
10
|
+
basename = "%s_%05d%s" % [fname_seed, Process.pid, suffix]
|
|
11
|
+
|
|
12
|
+
[dirname, basename].join('/').tap {|id| yield id }
|
|
13
|
+
end
|
|
14
|
+
module_function :with_new_identifier
|
|
4
15
|
end
|
|
5
16
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Adhoq
|
|
2
|
+
module Storage
|
|
3
|
+
class FogStorage
|
|
4
|
+
def store(suffix = nil, seed = Time.now, &block)
|
|
5
|
+
Adhoq::Storage.with_new_identifier(suffix, seed) do |identifier|
|
|
6
|
+
io = yield
|
|
7
|
+
io.rewind
|
|
8
|
+
|
|
9
|
+
directory.files.create(key: identifier, body: io, public: false)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def get(identifier)
|
|
14
|
+
get_raw(identifier).body
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get_raw(identifier)
|
|
18
|
+
directory.files.head(identifier)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -1,44 +1,25 @@
|
|
|
1
|
+
require 'fog'
|
|
2
|
+
|
|
1
3
|
module Adhoq
|
|
2
4
|
module Storage
|
|
3
|
-
class LocalFile
|
|
5
|
+
class LocalFile < FogStorage
|
|
4
6
|
attr_reader :root
|
|
5
7
|
|
|
6
8
|
def initialize(root_path)
|
|
7
|
-
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def identifier
|
|
11
|
-
"file://#{@root.realpath}"
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def store(suffix = nil, seed = Time.now, &block)
|
|
15
|
-
calculate_identifier(suffix, seed).tap do |identifier|
|
|
16
|
-
mkpath!(identifier)
|
|
9
|
+
path = Pathname.new(root_path)
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
file.flush
|
|
21
|
-
end
|
|
22
|
-
end
|
|
11
|
+
@fog = Fog::Storage.new(provider: 'Local', local_root: path.parent)
|
|
12
|
+
@dir = path.basename.to_s
|
|
23
13
|
end
|
|
24
14
|
|
|
25
|
-
def
|
|
26
|
-
|
|
15
|
+
def identifier
|
|
16
|
+
"file://#{[@fog.local_root, @dir].join('/')}"
|
|
27
17
|
end
|
|
28
18
|
|
|
29
19
|
private
|
|
30
20
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
basename = "%s_%05d%s" % [fname_seed, Process.pid, suffix]
|
|
35
|
-
|
|
36
|
-
identifier = [dirname, basename].join('/')
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def mkpath!(identifier)
|
|
40
|
-
dir = identifier.split('/').first
|
|
41
|
-
(@root + dir).mkpath
|
|
21
|
+
def directory
|
|
22
|
+
@fog.directories.get(@dir) || @fog.directories.create(key: @dir)
|
|
42
23
|
end
|
|
43
24
|
end
|
|
44
25
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'fog'
|
|
2
|
+
|
|
3
|
+
module Adhoq
|
|
4
|
+
module Storage
|
|
5
|
+
class S3 < FogStorage
|
|
6
|
+
def initialize(bucket, s3_options = {})
|
|
7
|
+
@bucket = bucket
|
|
8
|
+
@s3 = Fog::Storage.new({provider: 'AWS'}.merge(s3_options))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def identifier
|
|
12
|
+
"s3://#{@bucket}"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def directory
|
|
18
|
+
return @directory if @directory
|
|
19
|
+
|
|
20
|
+
@directory = @s3.directories.get(@bucket) || @s3.directories.create(key: @bucket, public: false)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/adhoq/version.rb
CHANGED
data/spec/adhoq/executor_spec.rb
CHANGED
|
@@ -7,5 +7,18 @@ module Adhoq
|
|
|
7
7
|
|
|
8
8
|
specify { expect(executor.execute).to eq Adhoq::Result.new(%w[answer], [[42]]) }
|
|
9
9
|
end
|
|
10
|
+
|
|
11
|
+
describe '.select' do
|
|
12
|
+
specify 'Do not reflect write access' do
|
|
13
|
+
expect {
|
|
14
|
+
Executor.select(<<-INSERT_SQL.strip_heredoc)
|
|
15
|
+
INSERT INTO "adhoq_queries"
|
|
16
|
+
("description", "name", "query", "updated_at", "created_at")
|
|
17
|
+
VALUES
|
|
18
|
+
("description", "name", "SELECT 1", "NOW", "NOW")
|
|
19
|
+
INSERT_SQL
|
|
20
|
+
}.not_to change(Adhoq::Query, :count)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
10
23
|
end
|
|
11
24
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Adhoq
|
|
2
|
+
RSpec.describe GlobalVariable, type: :model do
|
|
3
|
+
def reset_storage_config(*storage_config)
|
|
4
|
+
Adhoq.instance_variable_set('@current_storage', nil)
|
|
5
|
+
Adhoq.config.storage = storage_config
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
around(:each) do |example|
|
|
9
|
+
begin
|
|
10
|
+
original_config = Adhoq.config.storage
|
|
11
|
+
example.run
|
|
12
|
+
ensure
|
|
13
|
+
reset_storage_config(*original_config)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context 'config.storage = [:local_file, ....]' do
|
|
18
|
+
before do
|
|
19
|
+
reset_storage_config(:local_file, Rails.root + "/tmp/adhoq/#{Rails.env}")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
specify do
|
|
23
|
+
expect(Adhoq.current_storage).to be_instance_of Adhoq::Storage::LocalFile
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'config.storage = [:s3, ....]' do
|
|
28
|
+
before do
|
|
29
|
+
reset_storage_config(:s3, 'my-bucket-name', aws_access_key_id: 'key-id', aws_secret_access_key: 'secret', region: 'paris-01')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
specify do
|
|
33
|
+
expect(Adhoq.current_storage).to be_instance_of Adhoq::Storage::S3
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Adhoq
|
|
2
|
+
RSpec.describe Reporter::Xlsx, type: :model do
|
|
3
|
+
context 'create xlsx report' do
|
|
4
|
+
let(:report_data) do
|
|
5
|
+
Adhoq::Reporter.generate(Adhoq::AdhocExecution.new('xlsx', <<-SQL.strip_heredoc))
|
|
6
|
+
SELECT "hello" AS name ,"English greeting message" AS description
|
|
7
|
+
SQL
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
specify do
|
|
11
|
+
expect(report_data.read).to have_values_in_xlsx_sheet([
|
|
12
|
+
%w[name description],
|
|
13
|
+
['hello', 'English greeting message']
|
|
14
|
+
])
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/spec/adhoq/storage_spec.rb
CHANGED
|
@@ -10,10 +10,20 @@ module Adhoq
|
|
|
10
10
|
let(:storage) { Storage::LocalFile.new(tempdir) }
|
|
11
11
|
|
|
12
12
|
let(:identifier) do
|
|
13
|
-
storage.store('.txt') {
|
|
13
|
+
storage.store('.txt') { StringIO.new("Hello adhoq!\n") }
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
specify { expect(storage.get(identifier)
|
|
16
|
+
specify { expect(storage.get(identifier)).to eq "Hello adhoq!\n" }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe Storage::S3, :fog_mock do
|
|
20
|
+
let(:storage) { Storage::S3.new('my-adhoq-bucket', aws_access_key_id: 'key_id', aws_secret_access_key: 'access_key') }
|
|
21
|
+
|
|
22
|
+
let(:identifier) do
|
|
23
|
+
storage.store('.txt') { StringIO.new("Hello adhoq!\n") }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
specify { expect(storage.get(identifier)).to eq "Hello adhoq!\n" }
|
|
17
27
|
end
|
|
18
28
|
end
|
|
19
29
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -2,13 +2,18 @@ ENV['RAILS_ENV'] ||= 'test'
|
|
|
2
2
|
require_relative 'dummy/config/environment'
|
|
3
3
|
|
|
4
4
|
require 'rspec/rails'
|
|
5
|
-
require 'factory_girl_rails'
|
|
6
5
|
|
|
6
|
+
require 'capybara/rspec'
|
|
7
|
+
require 'capybara/poltergeist'
|
|
8
|
+
require 'database_cleaner'
|
|
9
|
+
require 'factory_girl_rails'
|
|
7
10
|
require 'pry-byebug'
|
|
8
11
|
|
|
9
12
|
Rails.backtrace_cleaner.remove_silencers!
|
|
10
13
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f }
|
|
11
14
|
|
|
15
|
+
Capybara.default_driver = :poltergeist
|
|
16
|
+
|
|
12
17
|
RSpec.configure do |config|
|
|
13
18
|
config.expect_with :rspec do |expectations|
|
|
14
19
|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
@@ -18,7 +23,7 @@ RSpec.configure do |config|
|
|
|
18
23
|
mocks.verify_partial_doubles = true
|
|
19
24
|
end
|
|
20
25
|
|
|
21
|
-
config.use_transactional_fixtures =
|
|
26
|
+
config.use_transactional_fixtures = false
|
|
22
27
|
config.filter_run :focus
|
|
23
28
|
config.run_all_when_everything_filtered = true
|
|
24
29
|
|
|
@@ -33,4 +38,26 @@ RSpec.configure do |config|
|
|
|
33
38
|
|
|
34
39
|
config.include FactoryGirl::Syntax::Methods
|
|
35
40
|
Kernel.srand config.seed
|
|
41
|
+
|
|
42
|
+
config.around(:each, :fog_mock) do |example|
|
|
43
|
+
begin
|
|
44
|
+
Fog.mock!
|
|
45
|
+
Fog::Mock.reset
|
|
46
|
+
|
|
47
|
+
example.run
|
|
48
|
+
ensure
|
|
49
|
+
Fog.unmock!
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
config.before(:suite) do
|
|
54
|
+
DatabaseCleaner.strategy = :truncation
|
|
55
|
+
DatabaseCleaner.clean_with :truncation
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
config.around(:each) do |example|
|
|
59
|
+
DatabaseCleaner.cleaning do
|
|
60
|
+
example.run
|
|
61
|
+
end
|
|
62
|
+
end
|
|
36
63
|
end
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
require 'rspec/matchers'
|
|
2
2
|
require 'simple_xlsx_reader'
|
|
3
3
|
|
|
4
|
-
RSpec::Matchers.define :have_values_in_xlsx_sheet do |
|
|
4
|
+
RSpec::Matchers.define :have_values_in_xlsx_sheet do |expect_values|
|
|
5
5
|
match do |data|
|
|
6
|
-
|
|
6
|
+
@actual_values = extract_values(data)
|
|
7
|
+
expect(@actual_values).to eq expect_values
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
failure_message do
|
|
12
|
+
RSpec::Expectations.differ.diff_as_object(@actual_values, expect_values)
|
|
7
13
|
end
|
|
8
14
|
|
|
9
15
|
private
|
|
10
16
|
|
|
11
17
|
def extract_values(data)
|
|
12
18
|
Tempfile.open(%w[actual .xlsx], Dir.tmpdir, encoding: 'BINARY') do |f|
|
|
13
|
-
f.write data
|
|
19
|
+
f.write data
|
|
14
20
|
f.flush
|
|
15
21
|
|
|
16
22
|
sheet = SimpleXlsxReader::Document.new(f.path).sheets.first
|
metadata
CHANGED
|
@@ -1,31 +1,45 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: adhoq
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kyosuke MOROHASHI
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-10-
|
|
11
|
+
date: 2014-10-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.2'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: axlsx
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
16
30
|
requirements:
|
|
17
31
|
- - "~>"
|
|
18
32
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
33
|
+
version: '2.0'
|
|
20
34
|
type: :runtime
|
|
21
35
|
prerelease: false
|
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
37
|
requirements:
|
|
24
38
|
- - "~>"
|
|
25
39
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
40
|
+
version: '2.0'
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
42
|
+
name: coffee-rails
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
30
44
|
requirements:
|
|
31
45
|
- - ">="
|
|
@@ -39,7 +53,35 @@ dependencies:
|
|
|
39
53
|
- !ruby/object:Gem::Version
|
|
40
54
|
version: '0'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
56
|
+
name: fog
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.23'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.23'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: font-awesome-sass
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: 4.2.0
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: 4.2.0
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: jquery-rails
|
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
|
44
86
|
requirements:
|
|
45
87
|
- - ">="
|
|
@@ -53,7 +95,7 @@ dependencies:
|
|
|
53
95
|
- !ruby/object:Gem::Version
|
|
54
96
|
version: '0'
|
|
55
97
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
98
|
+
name: sass-rails
|
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|
|
58
100
|
requirements:
|
|
59
101
|
- - ">="
|
|
@@ -67,7 +109,7 @@ dependencies:
|
|
|
67
109
|
- !ruby/object:Gem::Version
|
|
68
110
|
version: '0'
|
|
69
111
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
112
|
+
name: slim-rails
|
|
71
113
|
requirement: !ruby/object:Gem::Requirement
|
|
72
114
|
requirements:
|
|
73
115
|
- - ">="
|
|
@@ -81,13 +123,27 @@ dependencies:
|
|
|
81
123
|
- !ruby/object:Gem::Version
|
|
82
124
|
version: '0'
|
|
83
125
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
126
|
+
name: capybara
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: 2.4.3
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: 2.4.3
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: database_cleaner
|
|
85
141
|
requirement: !ruby/object:Gem::Requirement
|
|
86
142
|
requirements:
|
|
87
143
|
- - ">="
|
|
88
144
|
- !ruby/object:Gem::Version
|
|
89
145
|
version: '0'
|
|
90
|
-
type: :
|
|
146
|
+
type: :development
|
|
91
147
|
prerelease: false
|
|
92
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
149
|
requirements:
|
|
@@ -95,13 +151,13 @@ dependencies:
|
|
|
95
151
|
- !ruby/object:Gem::Version
|
|
96
152
|
version: '0'
|
|
97
153
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
154
|
+
name: factory_girl_rails
|
|
99
155
|
requirement: !ruby/object:Gem::Requirement
|
|
100
156
|
requirements:
|
|
101
157
|
- - ">="
|
|
102
158
|
- !ruby/object:Gem::Version
|
|
103
159
|
version: '0'
|
|
104
|
-
type: :
|
|
160
|
+
type: :development
|
|
105
161
|
prerelease: false
|
|
106
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
163
|
requirements:
|
|
@@ -109,7 +165,7 @@ dependencies:
|
|
|
109
165
|
- !ruby/object:Gem::Version
|
|
110
166
|
version: '0'
|
|
111
167
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
168
|
+
name: launchy
|
|
113
169
|
requirement: !ruby/object:Gem::Requirement
|
|
114
170
|
requirements:
|
|
115
171
|
- - ">="
|
|
@@ -122,6 +178,20 @@ dependencies:
|
|
|
122
178
|
- - ">="
|
|
123
179
|
- !ruby/object:Gem::Version
|
|
124
180
|
version: '0'
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: poltergeist
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - "~>"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: 1.5.1
|
|
188
|
+
type: :development
|
|
189
|
+
prerelease: false
|
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - "~>"
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: 1.5.1
|
|
125
195
|
- !ruby/object:Gem::Dependency
|
|
126
196
|
name: pry-byebug
|
|
127
197
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -217,6 +287,7 @@ files:
|
|
|
217
287
|
- app/assets/javascripts/adhoq/bootstrap/tab.js
|
|
218
288
|
- app/assets/javascripts/adhoq/bootstrap/tooltip.js
|
|
219
289
|
- app/assets/javascripts/adhoq/bootstrap/transition.js
|
|
290
|
+
- app/assets/javascripts/adhoq/current_tables.js.coffee
|
|
220
291
|
- app/assets/javascripts/adhoq/previewer.js.coffee
|
|
221
292
|
- app/assets/stylesheets/adhoq/_bootstrap-compass.scss
|
|
222
293
|
- app/assets/stylesheets/adhoq/_bootstrap-mincer.scss
|
|
@@ -296,6 +367,7 @@ files:
|
|
|
296
367
|
- app/assets/stylesheets/adhoq/bootstrap/mixins/_vendor-prefixes.scss
|
|
297
368
|
- app/controllers/adhoq/application_controller.rb
|
|
298
369
|
- app/controllers/adhoq/authorization_methods.rb
|
|
370
|
+
- app/controllers/adhoq/current_tables_controller.rb
|
|
299
371
|
- app/controllers/adhoq/executions_controller.rb
|
|
300
372
|
- app/controllers/adhoq/previews_controller.rb
|
|
301
373
|
- app/controllers/adhoq/queries_controller.rb
|
|
@@ -306,6 +378,7 @@ files:
|
|
|
306
378
|
- app/models/adhoq/time_based_orders.rb
|
|
307
379
|
- app/views/adhoq/application/_global_nav.html.slim
|
|
308
380
|
- app/views/adhoq/application/_sidebar_queries_index.html.slim
|
|
381
|
+
- app/views/adhoq/current_tables/index.html.slim
|
|
309
382
|
- app/views/adhoq/previews/create.html.slim
|
|
310
383
|
- app/views/adhoq/previews/statement_invalid.html.slim
|
|
311
384
|
- app/views/adhoq/queries/_form.html.slim
|
|
@@ -320,6 +393,7 @@ files:
|
|
|
320
393
|
- db/migrate/20141006014750_create_adhoq_executions.rb
|
|
321
394
|
- db/migrate/20141007052308_create_adhoq_reports.rb
|
|
322
395
|
- lib/adhoq.rb
|
|
396
|
+
- lib/adhoq/adhoc_execution.rb
|
|
323
397
|
- lib/adhoq/configuration.rb
|
|
324
398
|
- lib/adhoq/engine.rb
|
|
325
399
|
- lib/adhoq/error.rb
|
|
@@ -329,16 +403,22 @@ files:
|
|
|
329
403
|
- lib/adhoq/reporter/xlsx.rb
|
|
330
404
|
- lib/adhoq/result.rb
|
|
331
405
|
- lib/adhoq/storage.rb
|
|
406
|
+
- lib/adhoq/storage/fog_storage.rb
|
|
332
407
|
- lib/adhoq/storage/local_file.rb
|
|
408
|
+
- lib/adhoq/storage/s3.rb
|
|
333
409
|
- lib/adhoq/version.rb
|
|
334
410
|
- lib/tasks/adhoq_tasks.rake
|
|
335
411
|
- spec/adhoq/executor_spec.rb
|
|
412
|
+
- spec/adhoq/global_variable_spec.rb
|
|
413
|
+
- spec/adhoq/reporter/xlsx_spec.rb
|
|
336
414
|
- spec/adhoq/storage_spec.rb
|
|
337
415
|
- spec/factories/adhoq_queries.rb
|
|
338
416
|
- spec/models/adhoq/execution_spec.rb
|
|
339
417
|
- spec/models/adhoq/query_spec.rb
|
|
340
418
|
- spec/models/adhoq/report_spec.rb
|
|
341
419
|
- spec/spec_helper.rb
|
|
420
|
+
- spec/support/codeclimate_reporter.rb
|
|
421
|
+
- spec/support/feature_spec_helper.rb
|
|
342
422
|
- spec/support/have_values_in_xlsx_sheet_matcher.rb
|
|
343
423
|
homepage: https://github.com/esminc/adhoq
|
|
344
424
|
licenses:
|
|
@@ -366,10 +446,14 @@ specification_version: 4
|
|
|
366
446
|
summary: DB management console in the wild.
|
|
367
447
|
test_files:
|
|
368
448
|
- spec/adhoq/executor_spec.rb
|
|
449
|
+
- spec/adhoq/global_variable_spec.rb
|
|
450
|
+
- spec/adhoq/reporter/xlsx_spec.rb
|
|
369
451
|
- spec/adhoq/storage_spec.rb
|
|
370
452
|
- spec/factories/adhoq_queries.rb
|
|
371
453
|
- spec/models/adhoq/execution_spec.rb
|
|
372
454
|
- spec/models/adhoq/query_spec.rb
|
|
373
455
|
- spec/models/adhoq/report_spec.rb
|
|
456
|
+
- spec/support/codeclimate_reporter.rb
|
|
457
|
+
- spec/support/feature_spec_helper.rb
|
|
374
458
|
- spec/support/have_values_in_xlsx_sheet_matcher.rb
|
|
375
459
|
- spec/spec_helper.rb
|