Hello, I have attached the patch for the conjunctive search. Raw sql commands are the following: First I find files with the ctags. (there are 2 tags in the following case) SELECT ctags.file_id AS file_id FROM ctags JOIN files ON files.id = ctags.file_id WHERE ctags.tag IN (:tag_1, :tag_2) GROUP BY ctags.file_id HAVING count(DISTINCT ctags.tag) = 2 then i use the ids i recovered to find the package names etc. (there are 4 ids as the first command had 4 results.) SELECT files.id AS file_id, package_names.name AS package, packages.version AS version, files.path AS path FROM files, package_names, packages WHERE files.package_id = packages.id AND files.id IN (:id_1, :id_2, :id_3, :id_4) AND packages.name_id = package_names.id Cheers
From 34e6c018afeba3e633afebe80a77ca4e9a777a59 Mon Sep 17 00:00:00 2001
From: Orestis Ioannou <orestis@oioannou.com>
Date: Thu, 12 Mar 2015 13:53:34 +0100
Subject: [PATCH] Webapp: Add conjunctive search for ctags
Closes: #761867
---
debsources/app/sources/routes.py | 9 +++++
.../app/sources/templates/sources/test_ctag.html | 43 ++++++++++++++++++++++
debsources/app/views.py | 16 ++++++--
debsources/models.py | 32 ++++++++++++++++
debsources/tests/test_webapp.py | 7 ++++
5 files changed, 104 insertions(+), 3 deletions(-)
create mode 100644 debsources/app/sources/templates/sources/test_ctag.html
diff --git a/debsources/app/sources/routes.py b/debsources/app/sources/routes.py
index 1ac8282..eec69c3 100644
--- a/debsources/app/sources/routes.py
+++ b/debsources/app/sources/routes.py
@@ -198,6 +198,15 @@ bp_sources.add_url_rule(
err_func=ErrorHandler('sources'),
pagination=True))
+# CtagView
+bp_sources.add_url_rule(
+ '/test_ctag/',
+ view_func=CtagView.as_view(
+ 'test_ctag',
+ render_func=bind_render('sources/test_ctag.html'),
+ err_func=ErrorHandler('sources'),
+ pagination=True))
+
# api
bp_sources.add_url_rule(
diff --git a/debsources/app/sources/templates/sources/test_ctag.html b/debsources/app/sources/templates/sources/test_ctag.html
new file mode 100644
index 0000000..fa5e41e
--- /dev/null
+++ b/debsources/app/sources/templates/sources/test_ctag.html
@@ -0,0 +1,43 @@
+{#
+ Copyright (C) 2013 Matthieu Caneill <matthieu.caneill@gmail.com>
+ License: GNU Affero General Public License, version 3 or above.
+#}
+{# copied from templates/ctag.html #}
+
+{% extends "sources/base.html" %}
+n
+{% block title %}Ctag: {{ ctag }}
+{% if package %}(in package {{ package }}){% endif %}
+(page {{ page }}){% endblock %}
+
+{% block breadcrumbs %}ctag / {{ sha256 }}{% endblock %}
+
+{% block content %}
+
+<h2>{{ self.title() }}</h2>
+
+{{ count }} result{% if count >= 2 %}s{% endif %}:
+
+<ul>
+ {% for result in results %}
+ <li>
+ {% if conjunctive %}
+ <a href="{{ url_for('.source',
+ path_to="%s/%s/%s" % (result.package, result.version,
+ result.path)) }}">
+ {{ result.package }}/{{ result.version }}/{{ result.path }}</a>
+ {% else %}
+ <a href="{{ url_for('.source',
+ path_to="%s/%s/%s" % (result.package, result.version,
+ result.path),
+ hl = result.line,
+ _anchor="L%d" % result.line) }}">
+ {{ result.package }}/{{ result.version }}/{{ result.path }}</a>
+ {% endif %}
+ </li>
+ {% endfor %}
+</ul>
+
+{{ macros.render_pagination(pagination) }}
+
+{% endblock %}
diff --git a/debsources/app/views.py b/debsources/app/views.py
index ba27494..99bc2b8 100644
--- a/debsources/app/views.py
+++ b/debsources/app/views.py
@@ -425,8 +425,17 @@ class CtagView(GeneralView):
else:
pagination = None
slice_ = None
- count, results = Ctag.find_ctag(session, ctag, slice_=slice_,
- package=package)
+
+ conjunctive = False
+ if ',' in ctag:
+ ctags = ctag.split(',')
+ conjunctive = True
+ (count, results) = Ctag.conjunctive_search(session,
+ ctags, slice_=slice_,
+ package=package)
+ else:
+ (count, results) = Ctag.find_ctag(session, ctag, slice_=slice_,
+ package=package)
if self.d.get('pagination'):
pagination = Pagination(page, offset, count)
else:
@@ -437,7 +446,8 @@ class CtagView(GeneralView):
count=count,
page=page,
package=package,
- pagination=pagination)
+ pagination=pagination,
+ conjunctive=conjunctive)
class PrefixView(GeneralView):
diff --git a/debsources/models.py b/debsources/models.py
index e4d05fc..94d4f42 100644
--- a/debsources/models.py
+++ b/debsources/models.py
@@ -386,6 +386,38 @@ class Ctag(Base):
for res in results.all()]
return (count, results)
+ @staticmethod
+ def conjunctive_search(session, ctags, package=None, slice_=None):
+ find_files = (session.query(Ctag.file_id.label("file_id"))
+ .join(File)
+ .filter(Ctag.tag.in_(ctags))
+ .group_by(Ctag.file_id)
+ .having(sql_func.count(Ctag.tag.distinct())
+ == len(ctags))
+ )
+
+ results = (session.query(File.id.label("file_id"),
+ PackageName.name.label("package"),
+ Package.version.label("version"),
+ File.path.label("path"),
+ )
+ .filter(File.package_id == Package.id)
+ .filter(File.id.in_(find_files.all()))
+ .filter(Package.name_id == PackageName.id)
+ )
+ if package is not None:
+ results = results.filter(PackageName.name == package)
+ results = results.order_by(File.id, File.path)
+ count = results.count()
+ if slice_ is not None:
+ results = results.slice(slice_[0], slice_[1])
+ results = [dict(package=res.package,
+ version=res.version,
+ path=res.path,
+ id=res.file_id)
+ for res in results.all()]
+ return (count, results)
+
class Metric(Base):
__tablename__ = 'metrics'
diff --git a/debsources/tests/test_webapp.py b/debsources/tests/test_webapp.py
index d4eb3c8..c5cf3bd 100644
--- a/debsources/tests/test_webapp.py
+++ b/debsources/tests/test_webapp.py
@@ -422,6 +422,13 @@ class DebsourcesTestCase(unittest.TestCase, DbTestFixture):
self.assertEqual(rv["count"], 113)
self.assertEqual(len(rv["results"]), 113)
+ def test_api_conjunctive_search_ctag(self):
+ rv = json.loads(self.app.get('/api/ctag/?ctag=size,main').data)
+ self.assertEqual(len(rv["results"]), 4)
+ self.assertEqual(rv["results"][3], {'path': 'examples/input.c',
+ 'version': u'0.99.beta17-1',
+ 'id': 3891, 'package': u'libcaca'})
+
def test_api_search_ctag_within_package(self):
rv = json.loads(self.app.get(
'/api/ctag/?ctag=name&package=ledger').data)
--
2.1.4
Attachment:
signature.asc
Description: OpenPGP digital signature