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')