Fix semantic search SQL: CAST instead of :: for SQLAlchemy text() #161

Merged
forgejo_admin merged 1 commit from 160-fix-semantic-search-sql-sqlalchemy-text into main 2026-03-14 18:10:47 +00:00

Summary

SQLAlchemy's text() fails to bind :query_vec when followed by ::vector (PostgreSQL typecast syntax). The parameter is never recognized, causing semantic search to fail at runtime. This replaces all 4 occurrences with CAST(:query_vec AS vector), which SQLAlchemy parses correctly.

Changes

  • src/pal_e_docs/routes/notes.py — replaced :query_vec::vector with CAST(:query_vec AS vector) in 4 locations:
    • _semantic_search_notes() SELECT clause (line 312)
    • _semantic_search_notes() ORDER BY clause (line 317)
    • semantic_search() SELECT clause (line 594)
    • semantic_search() ORDER BY clause (line 599)

Test Plan

  • All 497 tests pass (pytest tests/ -v)
  • Ruff lint and format clean

Review Checklist

  • Changes are minimal and scoped to the issue
  • All tests pass
  • Ruff lint and format clean
  • No unrelated changes included
## Summary SQLAlchemy's `text()` fails to bind `:query_vec` when followed by `::vector` (PostgreSQL typecast syntax). The parameter is never recognized, causing semantic search to fail at runtime. This replaces all 4 occurrences with `CAST(:query_vec AS vector)`, which SQLAlchemy parses correctly. ## Changes - `src/pal_e_docs/routes/notes.py` — replaced `:query_vec::vector` with `CAST(:query_vec AS vector)` in 4 locations: - `_semantic_search_notes()` SELECT clause (line 312) - `_semantic_search_notes()` ORDER BY clause (line 317) - `semantic_search()` SELECT clause (line 594) - `semantic_search()` ORDER BY clause (line 599) ## Test Plan - All 497 tests pass (`pytest tests/ -v`) - Ruff lint and format clean ## Review Checklist - [x] Changes are minimal and scoped to the issue - [x] All tests pass - [x] Ruff lint and format clean - [x] No unrelated changes included ## Related - Closes forgejo_admin/pal-e-docs#160
Fix semantic search SQL: use CAST instead of :: typecast for SQLAlchemy text()
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
be54eada71
SQLAlchemy's text() doesn't bind :query_vec when followed by ::vector
(PostgreSQL typecast syntax). Replace all 4 occurrences of
:query_vec::vector with CAST(:query_vec AS vector) so the parameter
is properly recognized and bound.

Closes forgejo_admin/pal-e-docs#160

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

PR #161 Review

BLOCKERS

None.

NITS

None.

SOP COMPLIANCE

  • Branch named after issue (160-fix-semantic-search-sql-sqlalchemy-text)
  • PR body follows template (Summary, Changes, Test Plan, Related)
  • Related references Closes forgejo_admin/pal-e-docs#160
  • No secrets committed
  • No unrelated changes (1 file, 4 additions, 4 deletions)
  • Tests pass (497 reported)

CODE REVIEW

Correctness: All 4 occurrences of :query_vec::vector replaced with CAST(:query_vec AS vector). Both functions are covered:

Location Function Clause Status
Line 312 _semantic_search_notes() SELECT Fixed
Line 317 _semantic_search_notes() ORDER BY Fixed
Line 594 semantic_search() SELECT Fixed
Line 599 semantic_search() ORDER BY Fixed

SQL semantics preserved: CAST(x AS vector) is equivalent to x::vector in PostgreSQL. The :: shorthand is just syntactic sugar for CAST(). The fix is correct because SQLAlchemy's text() parser treats :query_vec as a bind parameter name and cannot disambiguate the :: that immediately follows. CAST() eliminates the parsing ambiguity entirely.

No residual issues: Grep confirms zero remaining ::vector patterns in the file.

VERDICT: APPROVED

## PR #161 Review ### BLOCKERS None. ### NITS None. ### SOP COMPLIANCE - [x] Branch named after issue (`160-fix-semantic-search-sql-sqlalchemy-text`) - [x] PR body follows template (Summary, Changes, Test Plan, Related) - [x] Related references `Closes forgejo_admin/pal-e-docs#160` - [x] No secrets committed - [x] No unrelated changes (1 file, 4 additions, 4 deletions) - [x] Tests pass (497 reported) ### CODE REVIEW **Correctness:** All 4 occurrences of `:query_vec::vector` replaced with `CAST(:query_vec AS vector)`. Both functions are covered: | Location | Function | Clause | Status | |----------|----------|--------|--------| | Line 312 | `_semantic_search_notes()` | SELECT | Fixed | | Line 317 | `_semantic_search_notes()` | ORDER BY | Fixed | | Line 594 | `semantic_search()` | SELECT | Fixed | | Line 599 | `semantic_search()` | ORDER BY | Fixed | **SQL semantics preserved:** `CAST(x AS vector)` is equivalent to `x::vector` in PostgreSQL. The `::` shorthand is just syntactic sugar for `CAST()`. The fix is correct because SQLAlchemy's `text()` parser treats `:query_vec` as a bind parameter name and cannot disambiguate the `::` that immediately follows. `CAST()` eliminates the parsing ambiguity entirely. **No residual issues:** Grep confirms zero remaining `::vector` patterns in the file. ### VERDICT: APPROVED
forgejo_admin deleted branch 160-fix-semantic-search-sql-sqlalchemy-text 2026-03-14 18:10:47 +00:00
Sign in to join this conversation.
No description provided.