search: multi-word queries match by word, not the exact phrase
Global search did a single ilike('%CSF Roles%'), so any query with more than one
word required the exact contiguous phrase and usually returned nothing. Add
_word_match: split the query into words and AND them (OR across the searched
columns per word), so 'CSF Roles' matches a record with both words in any field,
any order. Applied across every domain (assets, applications, KB, employees
[selfhosted + external HR], notifications, hostnames, IP, custom fields,
vendor/model/type). External HR path uses a parameterized per-word LIKE.
This commit is contained in:
39
tests/test_core/test_search_multiword.py
Normal file
39
tests/test_core/test_search_multiword.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""Global search matches multi-word queries by WORD (every word, any order or
|
||||
field), not just the exact contiguous phrase.
|
||||
|
||||
Regression: 'CSF Roles' returned nothing because search did a single
|
||||
ilike('%CSF Roles%'). Now each word must match (ORed across fields), so a record
|
||||
with both words - even reversed or split - is found; a record with only one is
|
||||
not.
|
||||
"""
|
||||
from shopdb.core.models import AssetType, Asset
|
||||
|
||||
|
||||
def _seed(client, db, auth_headers, assetnumber, name):
|
||||
if not AssetType.query.filter_by(assettype='computer').first():
|
||||
db.session.add(AssetType(assettype='computer', pluginname='computer',
|
||||
tablename='computer', description='c'))
|
||||
db.session.commit()
|
||||
r = client.post('/api/computers', json={'assetnumber': assetnumber},
|
||||
headers=auth_headers)
|
||||
assert r.status_code == 201, r.get_json()
|
||||
asset = Asset.query.filter_by(assetnumber=assetnumber).first()
|
||||
asset.name = name
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def _titles(client, auth_headers, term):
|
||||
r = client.get(f'/api/search?q={term}', headers=auth_headers)
|
||||
assert r.status_code == 200, r.get_json()
|
||||
return {h['title'] for h in r.get_json()['data']['results']}
|
||||
|
||||
|
||||
def test_multiword_matches_all_words_any_order(client, db, auth_headers):
|
||||
_seed(client, db, auth_headers, 'MW-1', 'CSF Roles Alpha') # contiguous
|
||||
_seed(client, db, auth_headers, 'MW-2', 'Roles for the CSF Beta') # split/reversed
|
||||
_seed(client, db, auth_headers, 'MW-3', 'CSF only') # one word only
|
||||
|
||||
titles = _titles(client, auth_headers, 'CSF Roles')
|
||||
assert 'CSF Roles Alpha' in titles # exact phrase still works
|
||||
assert 'Roles for the CSF Beta' in titles # words split/reversed now match
|
||||
assert 'CSF only' not in titles # missing a word -> excluded
|
||||
Reference in New Issue
Block a user