fix(search): delete regex bare-JSON-prefix rewrite, use default subpaths

The regex rewrite that turned bare notes:/custom_fields: prefixes into
their subpath spelling was blind to quoting: content:"payment notes:
none" was silently rewritten mid-phrase into a notes-field search and
matched zero documents. whoosh-compat's FieldSpec now supports a
default subpath per JSON field (SubpathSpec(default=True)), which
resolves during parsing where quoting is already understood, so the
pre-parse string rewrite is no longer needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
stumpylog
2026-08-20 08:13:29 -07:00
co-authored by Claude Sonnet 5
parent 95b600ebdd
commit 0fb36dae43
4 changed files with 165 additions and 105 deletions
@@ -354,77 +354,6 @@ class TestUnquotedDateKeywordPhrases:
assert _matched_ids(backend, "title:previous month") == {wordy.pk}
class TestBareJsonFieldPrefixes:
""" "notes:foo"/"custom_fields:foo" were valid fielded searches before
this migration. whoosh-compat's registry only exposes them as JSON
subpaths, so parse_user_query rewrites the bare prefixes live: notes:
-> notes.note:, custom_fields: -> custom_fields.value:."""
def test_bare_notes_prefix_searches_note_text(
self,
backend: TantivyBackend,
) -> None:
alice = User.objects.create_user(username="alice")
with_note = Document.objects.create(
title="Has note",
content="x",
checksum="bare-notes-with",
)
Note.objects.create(document=with_note, user=alice, note="crocodile")
backend.add_or_update(with_note)
# This document's CONTENT contains the words a demoted text search
# would match; it must NOT match once the prefix addresses notes.
_index(
backend,
title="Notes about things",
content="notes crocodile mention",
checksum="bare-notes-decoy",
)
assert _matched_ids(backend, "notes:crocodile") == {with_note.pk}
def test_bare_custom_fields_prefix_searches_values(
self,
backend: TantivyBackend,
) -> None:
field = CustomField.objects.create(
name="Policy Number",
data_type=CustomField.FieldDataType.STRING,
)
with_value = Document.objects.create(
title="Has field",
content="x",
checksum="bare-cf-with",
)
CustomFieldInstance.objects.create(
document=with_value,
field=field,
value_text="crocodile",
)
backend.add_or_update(with_value)
_index(
backend,
title="Custom things",
content="custom fields crocodile",
checksum="bare-cf-decoy",
)
assert _matched_ids(backend, "custom_fields:crocodile") == {with_value.pk}
def test_subpath_spellings_are_untouched(
self,
backend: TantivyBackend,
) -> None:
bob = User.objects.create_user(username="bob")
doc = Document.objects.create(
title="Bob note",
content="x",
checksum="bare-subpath",
)
Note.objects.create(document=doc, user=bob, note="remark")
backend.add_or_update(doc)
assert _matched_ids(backend, "notes.user:bob") == {doc.pk}
assert _matched_ids(backend, "notes.note:remark") == {doc.pk}
class TestFieldAliases:
"""type:/path: are registry aliases for document_type:/storage_path:.
The only other alias coverage is parse-shape; these prove resolution