aleph_analytics 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/app/assets/javascripts/angular/aleph.js.es6 +6 -0
- data/app/assets/javascripts/angular/controllers/controllers.js.es6 +1 -0
- data/app/assets/javascripts/angular/controllers/running_result/running_result_index_controller.js.es6 +56 -0
- data/app/assets/javascripts/angular/filters/filters.js.es6 +24 -6
- data/app/assets/javascripts/angular/services/services.js.es6 +10 -0
- data/app/assets/stylesheets/application.css.sass +1 -0
- data/app/assets/stylesheets/running_results.css.sass +15 -0
- data/app/controllers/admin/base_controller.rb +11 -0
- data/app/controllers/admin/running_results_controller.rb +33 -0
- data/app/models/query_execution.rb +6 -1
- data/app/models/user.rb +4 -0
- data/app/views/layouts/application.html.haml +6 -0
- data/app/views/queries/_results.html.haml +1 -1
- data/app/views/results/_show.html.haml +2 -2
- data/app/views/running_results/_index.html.haml +14 -0
- data/app/views/running_results/_index_item.html.haml +32 -0
- data/app/views/running_results/_index_sort_bar.html.haml +28 -0
- data/app/views/visualizations/_show.html.haml +2 -2
- data/config/example/redshift.yml +1 -0
- data/config/example/table_blacklist.yml +7 -0
- data/config/initializers/01_internalize_configurations.rb +4 -0
- data/config/initializers/pester.rb +2 -2
- data/config/initializers/rails_admin.rb +1 -1
- data/config/routes.rb +5 -0
- data/lib/csv_service.rb +4 -0
- data/lib/redshift_pg/connection.rb +5 -1
- data/lib/schemas/descriptor.rb +11 -1
- data/lib/schemas/paginate.rb +1 -1
- data/lib/tasks/karma.rake +1 -1
- data/lib/tasks/resque.rake +22 -0
- data/public/assets/.sprockets-manifest-61519c86aab355aa148c9e7c78293a9e.json +1 -0
- data/public/assets/angular/{aleph.js-48037f371a59a5ffaff68fd517163d50.es6 → aleph.js-4356bfc80f5b7dd3a9c9fdfacc6c8e7b.es6} +6 -0
- data/public/assets/angular/controllers/{controllers.js-94cb19ce7a5c88bfe6832a75a90b39d6.es6 → controllers.js-45fce398a9c2c371df9ffc32e8dbed84.es6} +1 -0
- data/public/assets/angular/controllers/running_result/running_result_index_controller.js-ce5ccd9d6fd27d6fea0c2c775d65a664.es6 +56 -0
- data/public/assets/angular/filters/filters.js-5d27b210896e5d5382b265ca12c96980.es6 +45 -0
- data/public/assets/angular/services/{services.js-6225c5ea24a9082506d1932d7884b53b.es6 → services.js-855551e8fa01a9a3c05115c4c9fdf7db.es6} +10 -0
- data/public/assets/{application-b990345b1178d3d77974c9ea035650ae.js → application-8bc9d85ca89b3c85e03f7d06948d2e87.js} +5 -5
- data/public/assets/{application-18bf9378371fb83c5d7714ee63887d6d.css → application-b3586e5b2749cef985bebb24246f95b6.css} +1 -1
- data/public/assets/resque_web/{application-705d1a4a22a72f773a8cd5c70ef9b284.js → application-4218536633ae4c535133fe1455d54cbc.js} +4 -4
- metadata +20 -10
- data/public/assets/.sprockets-manifest-ee5031d89f2eb0b53eb8eee944d985cf.json +0 -1
- data/public/assets/angular/filters/filters.js-48cdb16fc89337e861c9f18ad57fd9bf.es6 +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b835017996e863027ccbad3617742ffd680cfcd
|
4
|
+
data.tar.gz: 567308aed9dec7a7ab5c34ef296f1ee6276d4503
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee415ff8e6d34fd5275000d91564a19052156b7ea456a5af370cfbd546ef5d3a27760feeeb0e122fc1ea9251efb5fe5df7ed155beee3dcfff4c4a5e24e2db32f
|
7
|
+
data.tar.gz: 723ef552f7f7661ae409e4d1a6d1dc6cee7188666584a78462bdd9d893cbd17ba5c9476895cc93c9e7653fb106119bb4ab3baa8b614607c814f8a2e96cf76a2e
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file using [Semantic Versioning](http://semver.org/).
|
3
3
|
|
4
|
+
## [0.2.0] - 2017-09-12
|
5
|
+
### Features
|
6
|
+
- [Surface Running Queries](https://github.com/lumoslabs/aleph/issues/45)
|
7
|
+
- [Site wide, saved filter for schema](https://github.com/lumoslabs/aleph/issues/38)
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
- [Use trusty for travis](https://github.com/lumoslabs/aleph/issues/67)
|
11
|
+
- [Display 24-hour format](https://github.com/lumoslabs/aleph/issues/53)
|
12
|
+
- [Schema search should be able to handle numbers](https://github.com/lumoslabs/aleph/issues/59)
|
13
|
+
- [Clean up /tmp result files when query fails](https://github.com/lumoslabs/aleph/issues/37)
|
14
|
+
- [Increase schema query reties](https://github.com/lumoslabs/aleph/issues/64)
|
15
|
+
|
4
16
|
## [0.1.0] - 2017-04-27
|
5
17
|
### Features
|
6
18
|
- [Auto-complete on dot](https://github.com/lumoslabs/aleph/issues/48)
|
@@ -91,6 +91,12 @@
|
|
91
91
|
controller: 'SnippetIndexController',
|
92
92
|
controllerAs: 'snippetIdxCtrl'
|
93
93
|
})
|
94
|
+
.when('/running_results', {
|
95
|
+
title: 'RunningResults',
|
96
|
+
templateUrl: 'runningResultIndex',
|
97
|
+
controller: 'RunningResultIndexController',
|
98
|
+
controllerAs: 'runningResultsIdxCtrl'
|
99
|
+
})
|
94
100
|
.otherwise('/queries');
|
95
101
|
}]);
|
96
102
|
}(angular));
|
@@ -9,6 +9,7 @@
|
|
9
9
|
'alephControllers.queryReplController',
|
10
10
|
'alephControllers.alertIndexController',
|
11
11
|
'alephControllers.alertShowController',
|
12
|
+
'alephControllers.runningResultIndexController',
|
12
13
|
'alephControllers.snippetIndexController',
|
13
14
|
'alephControllers.singleResultShowController',
|
14
15
|
'alephServices',
|
@@ -0,0 +1,56 @@
|
|
1
|
+
!(angular => {
|
2
|
+
'use strict';
|
3
|
+
|
4
|
+
class RunningResultIndexController {
|
5
|
+
constructor($scope, ModelManager, $interval) {
|
6
|
+
this._$interval = $interval;
|
7
|
+
this._runningResultModelClasses = ModelManager.forModelName('runningResult');
|
8
|
+
this._RunningResult = this._runningResultModelClasses.modelClass();
|
9
|
+
this._RunningResults = this._runningResultModelClasses.collectionClass(this._RunningResult);
|
10
|
+
this.runningResults = new this._RunningResults();
|
11
|
+
this._pollForRunningResults();
|
12
|
+
|
13
|
+
$scope.$on('$destroy', () => {
|
14
|
+
this._$interval.cancel(this._intervalPromises);
|
15
|
+
});
|
16
|
+
|
17
|
+
// angular sorting
|
18
|
+
this.initialSortDirections = { started_at: true, author: true, duration_seconds: true, query_title: false };
|
19
|
+
}
|
20
|
+
|
21
|
+
isRepl(result) {
|
22
|
+
return !_.exists(result.item.query_id) || !_.exists(result.item.query_version_id);
|
23
|
+
}
|
24
|
+
|
25
|
+
getType(result) {
|
26
|
+
return this.isRepl(result) ? 'REPL' : 'SAVED';
|
27
|
+
}
|
28
|
+
|
29
|
+
setPredicate(predicate) {
|
30
|
+
if (predicate === this.predicate) {
|
31
|
+
this.reverse = !this.reverse;
|
32
|
+
} else {
|
33
|
+
this.predicate = predicate;
|
34
|
+
this.reverse = !!this.initialSortDirections[predicate];
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
getPredicate() {
|
39
|
+
return 'item.' + this.predicate;
|
40
|
+
}
|
41
|
+
|
42
|
+
// private methods
|
43
|
+
|
44
|
+
_pollForRunningResults() {
|
45
|
+
this.runningResults.initCollection();
|
46
|
+
this._intervalPromises = this._$interval(() => this.runningResults.initCollection(), 25000);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
RunningResultIndexController.$inject = ['$scope', 'ModelManager', '$interval'];
|
51
|
+
|
52
|
+
angular
|
53
|
+
.module('alephControllers.runningResultIndexController', ['alephServices'])
|
54
|
+
.controller('RunningResultIndexController', RunningResultIndexController);
|
55
|
+
|
56
|
+
}(angular));
|
@@ -11,17 +11,35 @@
|
|
11
11
|
})
|
12
12
|
|
13
13
|
.filter('humanReadableDuration', () => {
|
14
|
-
return (
|
14
|
+
return (originalSeconds) => {
|
15
15
|
let SECONDS_IN_HOUR = 3600;
|
16
16
|
let SECONDS_IN_MINUTE = 60;
|
17
17
|
|
18
|
-
let hours = Math.floor(
|
19
|
-
let minutes = Math.floor((
|
20
|
-
let seconds = Math.round(
|
18
|
+
let hours = Math.floor(originalSeconds / SECONDS_IN_HOUR);
|
19
|
+
let minutes = Math.floor((originalSeconds % SECONDS_IN_HOUR) / SECONDS_IN_MINUTE);
|
20
|
+
let seconds = Math.round(originalSeconds % SECONDS_IN_MINUTE);
|
21
21
|
|
22
|
-
return ((
|
23
|
-
((
|
22
|
+
return ((originalSeconds > SECONDS_IN_HOUR) ? hours + ' hours ' : '') +
|
23
|
+
((originalSeconds > SECONDS_IN_MINUTE) ? minutes + ' minutes ' : '') +
|
24
24
|
seconds + ' seconds';
|
25
25
|
};
|
26
|
+
})
|
27
|
+
|
28
|
+
.filter('runtimeDuration', () => {
|
29
|
+
return (originalSeconds) => {
|
30
|
+
let SECONDS_IN_DAY = 86400;
|
31
|
+
let SECONDS_IN_HOUR = 3600;
|
32
|
+
let SECONDS_IN_MINUTE = 60;
|
33
|
+
|
34
|
+
let days = Math.floor(originalSeconds / SECONDS_IN_DAY);
|
35
|
+
let hours = Math.floor((originalSeconds % SECONDS_IN_DAY) / SECONDS_IN_HOUR);
|
36
|
+
let minutes = Math.floor((originalSeconds % SECONDS_IN_HOUR) / SECONDS_IN_MINUTE);
|
37
|
+
let seconds = Math.round(originalSeconds % SECONDS_IN_MINUTE);
|
38
|
+
|
39
|
+
return ((originalSeconds > SECONDS_IN_DAY) ? days + ' days ' : '') +
|
40
|
+
((originalSeconds > SECONDS_IN_HOUR) ? hours + ':' : '00:') +
|
41
|
+
((originalSeconds > SECONDS_IN_MINUTE) ? minutes + ':' : '00:') +
|
42
|
+
seconds;
|
43
|
+
};
|
26
44
|
});
|
27
45
|
}(angular));
|
@@ -105,6 +105,16 @@
|
|
105
105
|
}
|
106
106
|
},
|
107
107
|
|
108
|
+
runningResult: {
|
109
|
+
//runningResult is a read only model
|
110
|
+
// no need for newItem since no need to figure out dirty awareness
|
111
|
+
newItem: {},
|
112
|
+
resource: {
|
113
|
+
path: '/running_results/:id.json',
|
114
|
+
parameters: {id: '@id'}
|
115
|
+
}
|
116
|
+
},
|
117
|
+
|
108
118
|
visualization: {
|
109
119
|
newItem: {
|
110
120
|
html_source: '',
|
@@ -0,0 +1,15 @@
|
|
1
|
+
.running-results-index
|
2
|
+
.query-body-preview
|
3
|
+
font-family: Menlo, Courier New, Courier
|
4
|
+
font-size: 9px
|
5
|
+
max-height: 100px
|
6
|
+
overflow-y: auto
|
7
|
+
|
8
|
+
.type-tag
|
9
|
+
background-color: tomato
|
10
|
+
|
11
|
+
.repl-tag-color
|
12
|
+
background-color: #5e8eae
|
13
|
+
|
14
|
+
.clipboard
|
15
|
+
margin-left: 14px
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Admin
|
2
|
+
class RunningResultsController < BaseController
|
3
|
+
|
4
|
+
RUNNING_RESULTS = <<-SQL
|
5
|
+
SELECT
|
6
|
+
title query_title,
|
7
|
+
compiled_body query_body,
|
8
|
+
TO_CHAR(results.started_at, 'YYYY-MM-DD HH24:MI:SS') started_at,
|
9
|
+
ROUND(EXTRACT(EPOCH FROM (now() - results.started_at)::INTERVAL)) duration_seconds,
|
10
|
+
users.name author,
|
11
|
+
users.role author_role,
|
12
|
+
queries.id query_id,
|
13
|
+
query_versions.id AS query_version_id,
|
14
|
+
version
|
15
|
+
FROM results
|
16
|
+
LEFT OUTER JOIN query_versions ON query_versions.id = results.query_version_id
|
17
|
+
LEFT OUTER JOIN queries ON query_versions.query_id = queries.id
|
18
|
+
INNER JOIN users ON results.owner_id = users.id
|
19
|
+
WHERE results.status = 'running'
|
20
|
+
SQL
|
21
|
+
|
22
|
+
respond_to :json
|
23
|
+
|
24
|
+
def index
|
25
|
+
respond_to do |format|
|
26
|
+
format.html
|
27
|
+
format.json do
|
28
|
+
render json: ActiveRecord::Base.connection.exec_query(RUNNING_RESULTS)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -4,6 +4,7 @@ class QueryExecution
|
|
4
4
|
|
5
5
|
def self.perform(result_id, role)
|
6
6
|
result = Result.find(result_id)
|
7
|
+
csv_service = CsvService.new(result_id)
|
7
8
|
|
8
9
|
unless Role.configured_connections.include?(role)
|
9
10
|
raise "Role '#{role}' does not have connection credentials configured."
|
@@ -31,9 +32,13 @@ class QueryExecution
|
|
31
32
|
result.mark_complete_with_count(row_count)
|
32
33
|
end
|
33
34
|
rescue *RedshiftPG::USER_ERROR_CLASSES => e
|
35
|
+
csv_service.clear_tmp_file
|
34
36
|
result.mark_failed!(e.message)
|
35
37
|
rescue => e
|
36
|
-
result
|
38
|
+
if result && csv_service
|
39
|
+
csv_service.clear_tmp_file
|
40
|
+
result.mark_failed!(e.message)
|
41
|
+
end
|
37
42
|
raise
|
38
43
|
end
|
39
44
|
end
|
data/app/models/user.rb
CHANGED
@@ -38,6 +38,8 @@
|
|
38
38
|
= render partial: 'alerts/show'
|
39
39
|
%script#snippetIndex{type: 'text/ng-template'}
|
40
40
|
= render partial: 'snippets/index'
|
41
|
+
%script#runningResultIndex{type: 'text/ng-template'}
|
42
|
+
= render partial: 'running_results/index'
|
41
43
|
%script#comments-template{type: 'text/ng-template'}
|
42
44
|
= render partial: 'queries/comments'
|
43
45
|
:javascript
|
@@ -64,6 +66,10 @@
|
|
64
66
|
%a.navbar-text{href: '/schemas', 'ng-class' => "{active: pathIncludes('schemas')}"}
|
65
67
|
%span.glyphicon.glyphicon-list.glyphicons-lg.glyphicon-med
|
66
68
|
Schemas
|
69
|
+
%a.navbar-text{href: '/running_results', 'ng-class' => "{active: pathIncludes('running_results')}",
|
70
|
+
'ng-if' => "'#{current_user.role}' == 'admin'"}
|
71
|
+
%span.glyphicon.glyphicon-plane.glyphicons-lg.glyphicon-low
|
72
|
+
Inflight
|
67
73
|
%ul.nav.navbar-nav.navbar-right
|
68
74
|
%li
|
69
75
|
- if user_signed_in?
|
@@ -11,7 +11,7 @@
|
|
11
11
|
%dd{ 'ng-bind' => 'resultsCtrl.query.item.version.version' }
|
12
12
|
%br
|
13
13
|
%dt Created:
|
14
|
-
%dd{ 'ng-bind' => 'resultsCtrl.query.item.version.created_at | date: "yyyy-MM-dd
|
14
|
+
%dd{ 'ng-bind' => 'resultsCtrl.query.item.version.created_at | date: "yyyy-MM-dd HH:mm:ss" : "UTC"' }
|
15
15
|
%br
|
16
16
|
%dt Author:
|
17
17
|
%dd{ 'ng-bind' => 'resultsCtrl.query.item.version.author_name' }
|
@@ -9,9 +9,9 @@
|
|
9
9
|
.run_duration{ 'ng-if' => 'resultCtrl.result.item.status == "complete" || resultCtrl.result.item.status == "failed"'}
|
10
10
|
Status: {{resultCtrl.result.item.status | uppercase}}
|
11
11
|
%br
|
12
|
-
Started: {{resultCtrl.result.item.started_at | date: 'yyyy-MM-dd
|
12
|
+
Started: {{resultCtrl.result.item.started_at | date: 'yyyy-MM-dd HH:mm:ss' : 'UTC'}}
|
13
13
|
%br
|
14
|
-
Ended: {{resultCtrl.result.item.completed_at | date: 'yyyy-MM-dd
|
14
|
+
Ended: {{resultCtrl.result.item.completed_at | date: 'yyyy-MM-dd HH:mm:ss' : 'UTC'}}
|
15
15
|
%br
|
16
16
|
Run duration: {{resultCtrl.result.item.run_duration | humanReadableDuration }}
|
17
17
|
%span.pull-right{ 'ng-if' => 'resultCtrl.result.item.status == "processing"' } {{resultCtrl.result.item.row_count}} rows returned so far, still processing full result and csv
|
@@ -0,0 +1,14 @@
|
|
1
|
+
.running-results-index
|
2
|
+
.row
|
3
|
+
.col-md-4
|
4
|
+
.input-group.input-group-sm
|
5
|
+
%label.input-group-addon
|
6
|
+
%i.glyphicon.glyphicon-search
|
7
|
+
%input.form-control{ 'id' => 'fulltext-search', 'ng-model' => 'searchText' }
|
8
|
+
.row.top30
|
9
|
+
.col-md-12.index-items
|
10
|
+
%ul
|
11
|
+
%li.item-header
|
12
|
+
= render partial: 'running_results/index_sort_bar'
|
13
|
+
%li.item-container{ 'ng-repeat' => 'result in runningResultsIdxCtrl.runningResults.collection | filter:searchText | orderBy:runningResultsIdxCtrl.getPredicate():runningResultsIdxCtrl.reverse' }
|
14
|
+
= render partial: 'running_results/index_item'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
.index-item
|
2
|
+
.row
|
3
|
+
.col-md-1
|
4
|
+
%span.label.type-tag{ 'ng-bind' => 'runningResultsIdxCtrl.getType(result)',
|
5
|
+
'ng-class' => "{'repl-tag-color': runningResultsIdxCtrl.isRepl(result)}"}
|
6
|
+
.col-md-2
|
7
|
+
%a{ 'ng-href' => '/queries/{{result.item.query_id}}/query_versions/{{result.item.query_version_id}}',
|
8
|
+
'ng-if' => '!runningResultsIdxCtrl.isRepl(result)' }
|
9
|
+
.ellipsis{ 'ng-bind' => 'result.item.query_title' }
|
10
|
+
%span{ 'ng-if' => 'runningResultsIdxCtrl.isRepl(result)' } -
|
11
|
+
.col-md-4
|
12
|
+
.row
|
13
|
+
.col-md-11.query-body-preview{ 'uib-popover' => '{{result.item.query_body}}',
|
14
|
+
'popover-trigger' => 'mouseenter',
|
15
|
+
'popover-popup-delay' => 1600,
|
16
|
+
'popover-placement' => 'right' }
|
17
|
+
%span{ 'ng-bind' => 'result.item.query_body'}
|
18
|
+
.col-md-1
|
19
|
+
%a.clipboard{ 'href' => '',
|
20
|
+
'text' => 'result.item.query_body',
|
21
|
+
'supported' => 'supported',
|
22
|
+
'clipboard' => '',
|
23
|
+
'uib-tooltip' => 'Copy SQL to clipboard',
|
24
|
+
'tooltip-popup-delay' => 1200,
|
25
|
+
'tooltip-placement' => 'right' }
|
26
|
+
%span.glyphicon.glyphicon-copy
|
27
|
+
.col-md-1
|
28
|
+
%span{ 'ng-bind' => 'result.item.author' }
|
29
|
+
.col-md-2
|
30
|
+
%span{ 'ng-bind' => 'result.item.started_at' }
|
31
|
+
.col-md-2
|
32
|
+
%span{ 'ng-bind' => 'result.item.duration_seconds | runtimeDuration' }
|
@@ -0,0 +1,28 @@
|
|
1
|
+
.sort-bar
|
2
|
+
.row
|
3
|
+
.col-md-1
|
4
|
+
%strong
|
5
|
+
TYPE
|
6
|
+
.col-md-2
|
7
|
+
%strong
|
8
|
+
%a{ 'ng-click' => 'runningResultsIdxCtrl.setPredicate("query_title")' }
|
9
|
+
QUERY
|
10
|
+
.glyphicon.glyphicon-sort.tiny-icon
|
11
|
+
.col-md-4
|
12
|
+
%strong
|
13
|
+
SQL BODY
|
14
|
+
.col-md-1
|
15
|
+
%strong
|
16
|
+
%a{ 'ng-click' => 'runningResultsIdxCtrl.setPredicate("author")' }
|
17
|
+
AUTHOR
|
18
|
+
.glyphicon.glyphicon-sort.tiny-icon
|
19
|
+
.col-md-2
|
20
|
+
%strong
|
21
|
+
%a{ 'ng-click' => 'runningResultsIdxCtrl.setPredicate("started_at")' }
|
22
|
+
STARTED AT
|
23
|
+
.glyphicon.glyphicon-sort.tiny-icon
|
24
|
+
.col-md-2
|
25
|
+
%strong
|
26
|
+
%a{ 'ng-click' => 'runningResultsIdxCtrl.setPredicate("duration_seconds")' }
|
27
|
+
RUN TIME
|
28
|
+
.glyphicon.glyphicon-sort.tiny-icon
|
@@ -78,6 +78,6 @@
|
|
78
78
|
%span{ 'ng-switch-when' => 'enqueued' }
|
79
79
|
Waiting to run.
|
80
80
|
%br
|
81
|
-
Enqueued at {{vizShowCtrl.sourceRenderer.latestResult().updated_at | date:'EEE yyyy-MM-dd
|
82
|
-
%span{ 'ng-switch-when' => 'running' } Running since {{vizShowCtrl.sourceRenderer.latestResult().updated_at | date:'EEE yyyy-MM-dd
|
81
|
+
Enqueued at {{vizShowCtrl.sourceRenderer.latestResult().updated_at | date:'EEE yyyy-MM-dd HH:mm:ss a' : 'UTC'}}.
|
82
|
+
%span{ 'ng-switch-when' => 'running' } Running since {{vizShowCtrl.sourceRenderer.latestResult().updated_at | date:'EEE yyyy-MM-dd HH:mm:ss a' : 'UTC'}}!
|
83
83
|
%span{ 'ng-switch-default' => true } Unknown status: "{{vizShowCtrl.sourceRenderer.latestResult().status}}"
|
data/config/example/redshift.yml
CHANGED
@@ -0,0 +1,7 @@
|
|
1
|
+
a_schema:
|
2
|
+
- a_blacklisted_table_for_schema_above
|
3
|
+
- each_entry_is_converted_to_ruby_regexep_and_matched_against_tables
|
4
|
+
- \Alets_say_i_dont_want_tables_starting_with*
|
5
|
+
another_schema:
|
6
|
+
- another_disliked_table
|
7
|
+
- ^((?!I_dont_want_any_tables_not_containing_this).)*$
|
@@ -68,3 +68,7 @@ end
|
|
68
68
|
# -------------------------------------------------
|
69
69
|
ATTRIBUTE_MAP = ingest.slurp('auth-attribute-map.yml')
|
70
70
|
File.open(Rails.root.join('config', 'attribute-map.yml'), 'w') { |f| f.write(ATTRIBUTE_MAP.to_yaml) } if ATTRIBUTE_MAP
|
71
|
+
|
72
|
+
# Schema Blacklist
|
73
|
+
# -------------------------------------------------
|
74
|
+
TABLE_BLACKLIST = ingest.slurp('table_blacklist.yml')
|
data/config/routes.rb
CHANGED
@@ -17,12 +17,17 @@ Rails.application.routes.draw do
|
|
17
17
|
resources :tags, only: [:index, :create, :destroy]
|
18
18
|
resources :alerts, only: [:show, :index, :create, :update, :destroy]
|
19
19
|
resources :snippets, only: [:show, :index, :create, :update, :destroy]
|
20
|
+
|
20
21
|
resources :query_versions, only: :show
|
21
22
|
resources :results, only: [:show, :create, :destroy]
|
22
23
|
resources :visualizations, only: [:create, :update, :destroy]
|
23
24
|
resources :schema_comments, only: [:create, :update, :destroy]
|
24
25
|
resources :result_csvs, only: :show
|
25
26
|
|
27
|
+
scope module: 'admin' do
|
28
|
+
resources :running_results, only: [:index]
|
29
|
+
end
|
30
|
+
|
26
31
|
mount ResqueWeb::Engine => "/resque_web"
|
27
32
|
|
28
33
|
root :to => 'application#index'
|
data/lib/csv_service.rb
CHANGED
@@ -12,6 +12,7 @@ module RedshiftPG
|
|
12
12
|
|
13
13
|
def initialize(config)
|
14
14
|
@config = config
|
15
|
+
@statement_timeout = config['statement_timeout']
|
15
16
|
end
|
16
17
|
|
17
18
|
def reconnect_on_failure(&block)
|
@@ -28,8 +29,11 @@ module RedshiftPG
|
|
28
29
|
end
|
29
30
|
|
30
31
|
private
|
32
|
+
|
31
33
|
def connect!
|
32
|
-
::PG.connect(pg_config)
|
34
|
+
::PG.connect(pg_config).tap do |conn|
|
35
|
+
conn.exec("SET statement_timeout to #{@statement_timeout}") if @statement_timeout
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
def pg_config
|
data/lib/schemas/descriptor.rb
CHANGED
@@ -70,7 +70,7 @@ module Schemas
|
|
70
70
|
end
|
71
71
|
|
72
72
|
if result
|
73
|
-
redis_store!(result.to_a)
|
73
|
+
redis_store!(filter_tables(result.to_a))
|
74
74
|
@cache = redis_retrieve
|
75
75
|
end
|
76
76
|
end
|
@@ -81,5 +81,15 @@ module Schemas
|
|
81
81
|
connection.pg_connection.exec(INFORMATION_SCHEMA_QUERY)
|
82
82
|
end
|
83
83
|
end
|
84
|
+
|
85
|
+
def filter_tables(schemas)
|
86
|
+
return schemas unless TABLE_BLACKLIST
|
87
|
+
|
88
|
+
schemas.reject do |column|
|
89
|
+
schema_blacklist = TABLE_BLACKLIST[column['table_schema']]
|
90
|
+
next unless schema_blacklist
|
91
|
+
schema_blacklist.any? { |bl_item| Regexp.new(bl_item).match(column['table_name']) }
|
92
|
+
end
|
93
|
+
end
|
84
94
|
end
|
85
95
|
end
|
data/lib/schemas/paginate.rb
CHANGED
data/lib/tasks/karma.rake
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
desc 'Clear pending tasks'
|
2
|
+
task 'resque:clear' => :environment do
|
3
|
+
queues = Resque.queues
|
4
|
+
queues.each do |queue_name|
|
5
|
+
puts "Clearing #{queue_name}..."
|
6
|
+
Resque.redis.del "queue:#{queue_name}"
|
7
|
+
end
|
8
|
+
|
9
|
+
# in case of scheduler - doesn't break if no scheduler module is installed
|
10
|
+
puts 'Clearing delayed...'
|
11
|
+
Resque.redis.keys('delayed:*').each do |key|
|
12
|
+
Resque.redis.del "#{key}"
|
13
|
+
end
|
14
|
+
Resque.redis.del 'delayed_queue_schedule'
|
15
|
+
|
16
|
+
puts 'Clearing failed jobs ... '
|
17
|
+
Resque::Failure.clear
|
18
|
+
|
19
|
+
puts 'Clearing stats...'
|
20
|
+
Resque.redis.set 'stat:failed', 0
|
21
|
+
Resque.redis.set 'stat:processed', 0
|
22
|
+
end
|