aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElena ``of Valhalla'' Grandi <valhalla@trueelena.org>2021-12-24 10:16:36 +0100
committerElena ``of Valhalla'' Grandi <valhalla@trueelena.org>2021-12-24 10:16:41 +0100
commitd9665cab55078aa6e0c6ca4dce4a2c7ea8c4177d (patch)
tree9cb0afaa480fef995a19e46672ad198a7512e0f1
parent0e4924ebca62b6767639aad773816a62c6a3c9af (diff)
Add support for search_aliases in the settings file.
Refs: https://todo.sr.ht/~valhalla/lesana/11
-rw-r--r--CHANGELOG.rst2
-rw-r--r--docs/source/man/lesana-search.rst5
-rw-r--r--docs/source/user/search.rst18
-rw-r--r--docs/source/user/settings.rst3
-rw-r--r--lesana/collection.py7
-rw-r--r--lesana/command.py15
-rw-r--r--tests/data/complex/settings.yaml3
-rw-r--r--tests/test_collection.py12
-rw-r--r--tests/test_commands.py18
9 files changed, 80 insertions, 3 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 48486ff..8b2d9c4 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -24,6 +24,8 @@ Unreleased
contents of a field.
* New property ``precision`` for ``decimal`` fields, to force rounding
values to that number of decimal digits.
+* New settings property ``search_aliases`` with a dict of values to be
+ filled in in a jinja2 template for a search query.
Bugfixes
--------
diff --git a/docs/source/man/lesana-search.rst b/docs/source/man/lesana-search.rst
index fff4b8e..f7bcf9c 100644
--- a/docs/source/man/lesana-search.rst
+++ b/docs/source/man/lesana-search.rst
@@ -7,7 +7,8 @@ SYNOPSIS
lesana search [--help] [--collection COLLECTION] [--template TEMPLATE] \
[--offset OFFSET] [--pagesize PAGESIZE] [--all] \
- [--sort FIELD1 [--sort FIELD2 ...]] [query [query ...]]
+ [--expand-query-template] [--sort FIELD1 [--sort FIELD2 ...]] \
+ [query [query ...]]
DESCRIPTION
===========
@@ -50,4 +51,6 @@ OPTIONS
This option can be added multiple times; prefix the name of the field
with ``-`` to reverse the results (e.g. ``--sort='-date'``).
+expand-query-template
+ Render search_aliases in the query as a jinja2 template
diff --git a/docs/source/user/search.rst b/docs/source/user/search.rst
index 41746a3..d14f37f 100644
--- a/docs/source/user/search.rst
+++ b/docs/source/user/search.rst
@@ -22,3 +22,21 @@ xapian for details.
.. _`Query Parser`: https://getting-started-with-xapian.readthedocs.io/en/latest/concepts/search/queryparser.html
+.. _search aliases:
+
+Search templates and ``search_aliases``
+=======================================
+
+In some contexts, search queries are rendered as jinja2 templates with
+the contents of the ``search_aliases`` property as set in
+``settings.yaml``.
+
+The values of those search aliases should be valid search snippets with
+the syntax documented above; it's usually a good idea to wrap them in
+parenthesis, so that they are easier to use in complex queries; e.g.::
+
+ my_alias: '(name:object OR name:thing)'
+
+can correctly be used in a query like::
+
+ {{ my_alias }} AND description:shiny
diff --git a/docs/source/user/settings.rst b/docs/source/user/settings.rst
index 2d3a3fa..ba14e37 100644
--- a/docs/source/user/settings.rst
+++ b/docs/source/user/settings.rst
@@ -20,6 +20,9 @@ It is a yaml file with a dict of properties and their values.
a list of field names (possibly prefixed by + or -) that are used by
default to sort results of searches in the collection.
The fields must be marked as sortable in their definition, see below.
+``search_aliases``:
+ a dict of <name>: <search snippet> which can be used in a query
+ template. For more details see :ref:`search aliases`
``fields``:
The list of fields used by the collection, as described below.
diff --git a/lesana/collection.py b/lesana/collection.py
index d51187f..e428ae1 100644
--- a/lesana/collection.py
+++ b/lesana/collection.py
@@ -334,6 +334,13 @@ class Collection(object):
)
return cache
+ def render_query_template(self, query):
+ """
+ Render a query template, filling it with search_aliases.
+ """
+ t = jinja2.Template(query)
+ return t.render(**self.settings.get('search_aliases', {}))
+
def start_search(self, querystring, sort_by=None):
"""
Prepare a search for querystring.
diff --git a/lesana/command.py b/lesana/command.py
index 92f82df..ac7eba2 100644
--- a/lesana/command.py
+++ b/lesana/command.py
@@ -291,6 +291,14 @@ class Search(Command):
dict(action='append', help='Sort results by a sortable field'),
),
(
+ ['--expand-query-template', '-e'],
+ {
+ 'action': 'store_true',
+ 'help':
+ 'Render search_aliases in the query as a jinja2 template',
+ },
+ ),
+ (
['query'],
{
'help': 'Xapian query to search in the collection',
@@ -315,16 +323,19 @@ class Search(Command):
offset = self.args.offset or 0
pagesize = self.args.pagesize or 12
collection = self.collection_class(self.args.collection)
+ query = self.args.query
+ if self.args.expand_query_template:
+ query = collection.render_query_template(query)
# sorted results require a less efficient full search rather
# than being able to use the list of all documents.
- if self.args.query == ['*'] and not (
+ if query == ['*'] and not (
self.args.sort
or getattr(collection.settings, 'default_sort', False)
):
results = collection.get_all_documents()
else:
collection.start_search(
- ' '.join(self.args.query),
+ ' '.join(query),
sort_by=self.args.sort
)
if self.args.all:
diff --git a/tests/data/complex/settings.yaml b/tests/data/complex/settings.yaml
index f4ad574..09e9c98 100644
--- a/tests/data/complex/settings.yaml
+++ b/tests/data/complex/settings.yaml
@@ -63,3 +63,6 @@ fields:
- name: price
type: decimal
precision: 2
+search_aliases:
+ nice: '(category:first OR category:second)'
+ bad: category:third
diff --git a/tests/test_collection.py b/tests/test_collection.py
index de349ed..1400f57 100644
--- a/tests/test_collection.py
+++ b/tests/test_collection.py
@@ -550,6 +550,18 @@ class testComplexCollection(unittest.TestCase):
entry = self.collection.entry_from_eid(eid)
self.assertEqual(entry.data['price'], "1.90")
+ def test_search_aliases(self):
+ search_query = "{{ nice }}"
+ search_query = self.collection.render_query_template(search_query)
+ print("QUERY IS", search_query)
+ self.collection.start_search(search_query)
+ res = self.collection.get_search_results()
+ matches = list(res)
+ self.assertEqual(len(matches), 2)
+ matches_ids = [m.eid for m in matches]
+ self.assertIn('8e9fa1ed3c1b4a30a6be7a98eda0cfa7', matches_ids)
+ self.assertIn('5084bc6e94f24dc6976629282ef30419', matches_ids)
+
class testCollectionWithErrors(unittest.TestCase):
def setUp(self):
diff --git a/tests/test_commands.py b/tests/test_commands.py
index 1a7d83b..91a8894 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -115,6 +115,7 @@ class testCommandsSimple(unittest.TestCase, CommandsMixin):
'offset': None,
'pagesize': None,
'sort': None,
+ 'expand_query_template': False,
'all': False,
}
streams = self._run_command(command.Search(), args)
@@ -205,6 +206,23 @@ class testCommandsComplex(unittest.TestCase, CommandsMixin):
self.assertIn('this: 1', streams['stdout'].getvalue())
self.assertEqual(streams['stderr'].getvalue(), '')
+ def test_search_template(self):
+ args = {
+ 'collection': self.tmpdir.name,
+ 'git': True,
+ 'template': False,
+ 'query': '{{ nice }}',
+ 'expand_query_template': True,
+ 'offset': None,
+ 'pagesize': None,
+ 'sort': None,
+ 'all': False,
+ }
+ streams = self._run_command(command.Search(), args)
+ self.assertIn('8e9fa1ed', streams['stdout'].getvalue())
+ self.assertIn('5084bc6e', streams['stdout'].getvalue())
+ self.assertEqual(streams['stderr'].getvalue(), '')
+
if __name__ == '__main__':
unittest.main()