From 6f6f952338efca60ca5db624d270dda5bb1175ff Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 26 Aug 2024 18:38:36 +0200 Subject: [PATCH] Factoids: Fix search results when single key matched 1. Display the key itself (in addition to the values), because searching factoids makes little sense without returning the key 2. Display only matching values, instead of all other values, because some filters act on values --- plugins/Factoids/plugin.py | 51 ++++++++++++++++++++++++++++++++++---- plugins/Factoids/test.py | 12 +++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/plugins/Factoids/plugin.py b/plugins/Factoids/plugin.py index cfa20d49b..0f9ea018e 100644 --- a/plugins/Factoids/plugin.py +++ b/plugins/Factoids/plugin.py @@ -815,6 +815,7 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler): join_factoids = False formats = [] criteria = [] + join_criteria = [] target = 'keys.key' predicateName = 'p' db = self.getDb(channel) @@ -836,20 +837,23 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler): criteria.append('TARGET LIKE ?') formats.append(self._sqlTrans(glob)) - if join_factoids: + def _join_factoids(): if 'factoids' not in tables: tables.append('factoids') tables.append('relations') - criteria.append( + join_criteria.append( 'factoids.id=relations.fact_id AND keys.id=relations.key_id' ) + if join_factoids: + _join_factoids() cursor = db.cursor() - sql = """SELECT keys.key FROM %s WHERE %s""" % \ - (', '.join(tables), ' AND '.join(criteria)) + sql = """SELECT DISTINCT keys.key FROM %s WHERE %s""" % \ + (', '.join(tables), ' AND '.join(criteria + join_criteria)) sql = sql + " ORDER BY keys.key" sql = sql.replace('TARGET', target) cursor.execute(sql, formats) + if cursor.rowcount == 0: irc.reply(_('No keys matched that query.')) elif cursor.rowcount == 1 and \ @@ -865,7 +869,44 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler): elif len(results) == 1 and \ self.registryValue('showFactoidIfOnlyOneMatch', channel, irc.network): - self.whatis(irc, msg, [channel, results[0][0]]) + ((key,),) = results + + # add the knowledge we gained, so avoid a full search again + join_criteria.append('keys.key=?') + formats.append(key) + + if not join_factoids: + # if they were not joined before, we need to join + # them now to get the values + _join_factoids() + + sql = """ + SELECT factoids.fact, (1 AND %s) FROM %s + WHERE %s + ORDER BY factoids.id + """ % \ + (' AND '.join(criteria), ', '.join(tables), + ' AND '.join(['keys.key=?', *join_criteria])) + sql = sql.replace('TARGET', target) + formats.append(key) + cursor.execute(sql, formats) + factoids = cursor.fetchall() + assert factoids # we had a result before, and still should now + if len(factoids) == 1: + ((fact, included),) = factoids + assert included # matched before, should still match now + irc.reply('%s is %s' % + (key, ircutils.standardSubstitute(irc, msg, fact))) + else: + factoidsS = [] + counter = 1 + for (fact, included) in factoids: + if included: + factoidsS.append(format('(#%i) %s', counter, + ircutils.standardSubstitute(irc, msg, fact))) + counter += 1 + irc.replies(factoidsS, prefixer=lambda s: '%s is %s' % (key, s), + joiner=', or ', onlyPrefixFirst=True) elif len(results) > 100: irc.reply(_('More than 100 keys matched that query; ' 'please narrow your query.')) diff --git a/plugins/Factoids/test.py b/plugins/Factoids/test.py index a600fd4c1..7e253c009 100644 --- a/plugins/Factoids/test.py +++ b/plugins/Factoids/test.py @@ -118,6 +118,18 @@ class FactoidsTestCase(ChannelPluginTestCase): self.assertRegexp('factoids search --author blahblah j*', 'No keys matched that query.') + def testSearchMultiFactoids(self): + self.assertNotError('learn water is wet') + self.assertResponse('factoids search --values we', 'water is wet') + self.assertNotError('learn water is H2O') + self.assertNotError('learn fire is hot') + self.assertResponse('factoids search --values we', 'water is (#1) wet') + self.assertResponse('factoids search --values H2', 'water is (#2) H2O') + + self.assertNotError('learn water is very wet') + self.assertResponse('factoids search --values we', + 'water is (#1) wet, or (#3) very wet') + def testWhatisOnNumbers(self): self.assertNotError('learn 911 is emergency number') self.assertRegexp('whatis 911', 'emergency number')