fix(core): make note_types search filter case-insensitive#912
Conversation
Bug #14 (integration bug hunt): the search_notes note_types filter was case-sensitive on both backends. The MCP tool documents note_types as case-insensitive and lowercases the input ('Chapter' -> 'chapter'), but the stored frontmatter type preserves its casing ('Chapter'), so the SQL comparison never matched capitalized types. Fix folds case on both ends: - SQLite: LOWER(json_extract(metadata, '$.note_type')) IN (...) with lowercased param values. - Postgres: replace JSONB '@>' containment with LOWER(metadata->>'note_type') IN (...) with lowercased param values. Values stay parameterized, so SQL-injection protection is unchanged. Adds the regression test from the integration bug hunt under test-int/mcp/test_search_note_types_case_insensitive.py (real DB/ASGI/MCP client, no mocks): a capitalized 'type: Chapter' note is now matched by note_types=['Chapter'], plus a lowercase control. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
|
Claude finished @phernandez's task in 1m 52s —— View job Code Review — PR #912:
|
Summary
The
search_notesnote_typesfilter was case-sensitive on both the SQLite and Postgres backends, despite the MCP tool documenting it as case-insensitive. The tool lowercases the input ("Chapter"->"chapter"), but the stored frontmattertypevalue preserves its original casing ("Chapter"), so the SQL comparison never matched capitalized types. A note withtype: Chapterwas findable by plain text search but invisible tosearch_notes(note_types=["Chapter"]).This fix folds case on both ends of the comparison.
Bugs fixed
canvastool to create json canvas files in obsidian. #14 —note_typesfilter is case-sensitive despite documented case-insensitivity (capitalized frontmattertypevalues were unfindable).sqlite_search_repository.py): wrap the column inLOWER(json_extract(metadata, '$.note_type'))and lowercase the parameter values.postgres_search_repository.py): replace the JSONB@>containment check (exact-match) withLOWER(metadata->>'note_type') IN (...)and lowercase the parameter values.Testing
Test came from the integration bug hunt; added under
test-int/mcp/test_search_note_types_case_insensitive.py(real DB / ASGI / MCP client, no mocks).uv run pytest test-int/mcp/test_search_note_types_case_insensitive.py -q --no-cov-> 2 passed (SQLite)BASIC_MEMORY_TEST_POSTGRES=1 uv run pytest test-int/mcp/test_search_note_types_case_insensitive.py -q --no-cov-> 2 passed (Postgres)uv run pytest tests/repository/test_search_repository.py test-int/mcp/test_search_integration.py -q --no-cov-> 50 passed (SQLite)BASIC_MEMORY_TEST_POSTGRES=1 uv run pytest tests/repository/test_postgres_search_repository.py tests/repository/test_search_repository.py -q --no-cov-> 47 passed, 12 skipped (Postgres)uv run ruff check(scoped files) /uv run ruff format ./uv run ty check src tests test-int-> all passRisk
Low. The change only affects the
note_typesfilter clause. Lowercasing the stored value at comparison time broadens matching to be case-insensitive (the documented behavior); the SQL-injection regression tests fornote_typesstill pass on both backends. No tool signature changed.🤖 Generated with Claude Code