diff --git a/rd_ui/app/scripts/controllers/controllers.js b/rd_ui/app/scripts/controllers/controllers.js index e3bdca53..82d48408 100644 --- a/rd_ui/app/scripts/controllers/controllers.js +++ b/rd_ui/app/scripts/controllers/controllers.js @@ -1,5 +1,5 @@ (function () { - var QuerySearchCtrl = function($scope, $location, Query) { + var QuerySearchCtrl = function($scope, $location, $filter, Query) { $scope.$parent.pageTitle = "Queries Search"; $scope.gridConfig = { @@ -27,6 +27,25 @@ 'label': 'Created At', 'map': 'created_at', 'formatFunction': dateFormatter + }, + { + 'label': 'Runtime', + 'map': 'runtime', + 'formatFunction': function (value) { + return $filter('durationHumanize')(value); + } + }, + { + 'label': 'Last Executed At', + 'map': 'retrieved_at', + 'formatFunction': dateFormatter + }, + { + 'label': 'Update Schedule', + 'map': 'ttl', + 'formatFunction': function (value) { + return $filter('refreshRateHumanize')(value); + } } ]; @@ -37,6 +56,7 @@ console.log(results); $scope.queries = _.map(results, function(query) { query.created_at = moment(query.created_at); + query.retrieved_at = moment(query.retrieved_at); return query; }); }); @@ -86,7 +106,7 @@ Query.query(function (queries) { $scope.allQueries = _.map(queries, function (query) { query.created_at = moment(query.created_at); - query.last_retrieved_at = moment(query.last_retrieved_at); + query.retrieved_at = moment(query.retrieved_at); return query; }); @@ -109,35 +129,17 @@ 'formatFunction': dateFormatter }, { - 'label': 'Runtime (avg)', - 'map': 'avg_runtime', - 'formatFunction': function (value) { - return $filter('durationHumanize')(value); - } - }, - { - 'label': 'Runtime (min)', - 'map': 'min_runtime', - 'formatFunction': function (value) { - return $filter('durationHumanize')(value); - } - }, - { - 'label': 'Runtime (max)', - 'map': 'max_runtime', + 'label': 'Runtime', + 'map': 'runtime', 'formatFunction': function (value) { return $filter('durationHumanize')(value); } }, { 'label': 'Last Executed At', - 'map': 'last_retrieved_at', + 'map': 'retrieved_at', 'formatFunction': dateFormatter }, - { - 'label': 'Times Executed', - 'map': 'times_retrieved' - }, { 'label': 'Update Schedule', 'map': 'ttl', @@ -146,6 +148,7 @@ } } ] + $scope.tabs = [ {"name": "My Queries", "key": "my"}, {"key": "all", "name": "All Queries"}, @@ -222,5 +225,5 @@ .controller('QueriesCtrl', ['$scope', '$http', '$location', '$filter', 'Query', QueriesCtrl]) .controller('IndexCtrl', ['$scope', 'Events', 'Dashboard', IndexCtrl]) .controller('MainCtrl', ['$scope', '$location', 'Dashboard', 'notifications', MainCtrl]) - .controller('QuerySearchCtrl', ['$scope', '$location', 'Query', QuerySearchCtrl]); + .controller('QuerySearchCtrl', ['$scope', '$location', '$filter', 'Query', QuerySearchCtrl]); })(); diff --git a/redash/controllers.py b/redash/controllers.py index 955257f3..bef43d07 100644 --- a/redash/controllers.py +++ b/redash/controllers.py @@ -281,7 +281,7 @@ class QuerySearchAPI(BaseResource): def get(self): term = request.args.get('q', '') - return [q.to_dict() for q in models.Query.search(term)] + return [q.to_dict(with_stats=True) for q in models.Query.search(term)] class QueryListAPI(BaseResource): diff --git a/redash/models.py b/redash/models.py index 4969c17d..0609302d 100644 --- a/redash/models.py +++ b/redash/models.py @@ -305,11 +305,8 @@ class Query(BaseModel): d['user_id'] = self._data['user'] if with_stats: - d['avg_runtime'] = self.avg_runtime - d['min_runtime'] = self.min_runtime - d['max_runtime'] = self.max_runtime - d['last_retrieved_at'] = self.last_retrieved_at - d['times_retrieved'] = self.times_retrieved + d['retrieved_at'] = self.retrieved_at + d['runtime'] = self.runtime if with_visualizations: d['visualizations'] = [vis.to_dict(with_query=False) @@ -319,15 +316,10 @@ class Query(BaseModel): @classmethod def all_queries(cls): - q = Query.select(Query, User, - peewee.fn.Count(QueryResult.id).alias('times_retrieved'), - peewee.fn.Avg(QueryResult.runtime).alias('avg_runtime'), - peewee.fn.Min(QueryResult.runtime).alias('min_runtime'), - peewee.fn.Max(QueryResult.runtime).alias('max_runtime'), - peewee.fn.Max(QueryResult.retrieved_at).alias('last_retrieved_at'))\ + q = Query.select(Query, User, QueryResult.retrieved_at, QueryResult.runtime)\ .join(QueryResult, join_type=peewee.JOIN_LEFT_OUTER)\ .switch(Query).join(User)\ - .group_by(Query.id, User.id) + .group_by(Query.id, User.id, QueryResult.id) return q @@ -351,7 +343,7 @@ class Query(BaseModel): @classmethod def search(cls, term): # This is very naive implementation of search, to be replaced with PostgreSQL full-text-search solution. - return cls.select().where((cls.name**"%{}%".format(term)) | (cls.description**"%{}%".format(term))) + return cls.all_queries().where((cls.name**"%{}%".format(term)) | (cls.description**"%{}%".format(term))) @classmethod def update_instance(cls, query_id, **kwargs): @@ -371,6 +363,14 @@ class Query(BaseModel): self.api_key = hashlib.sha1( u''.join((str(time.time()), self.query, str(self._data['user']), self.name)).encode('utf-8')).hexdigest() + @property + def runtime(self): + return self.latest_query_data.runtime + + @property + def retrieved_at(self): + return self.latest_query_data.retrieved_at + def __unicode__(self): return unicode(self.id) diff --git a/tests/test_models.py b/tests/test_models.py index d210f567..68327f97 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -52,6 +52,16 @@ class QueryTest(BaseTestCase): self.assertIn(q2, queries) self.assertNotIn(q3, queries) + def test_search_returns_extended_info_queries(self): + query = query_factory.create(description="Testing search") + qr = query_result_factory.create() + query.latest_query_data = qr + query.save() + queries = models.Query.search("search") + + self.assertIsNotNone(queries[0].retrieved_at) + self.assertIsNotNone(queries[0].runtime) + class QueryResultTest(BaseTestCase): def setUp(self):