fix: Prevent ISE when tsquery tail interleaves operator and escape chars (#12475)

When a user query produces a pg-tsquery output ending in mixed `&` and `\`
characters (e.g. `"plugins"&\`), stripping them with separate single-char
regexes in a fixed order could leave a dangling `&` operator, causing
Postgres to reject the query with "no operand in tsquery".

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Tom Moor
2026-05-26 20:10:49 -04:00
committed by GitHub
parent 15213bbeb0
commit a23b04c8fa
2 changed files with 12 additions and 4 deletions
@@ -1412,5 +1412,13 @@ describe("PostgresSearchProvider", () => {
`"this<->is<->a<->test"`
);
});
it("should strip interleaved trailing operator and escape characters", () => {
// pg-tsquery reorders trailing operators and may emit a tail like
// `&\` that, if stripped one character at a time in the wrong order,
// leaves a dangling `&` and triggers "no operand in tsquery".
expect(PostgresSearchProvider.webSearchQuery(`"plugins"\\&`)).toBe(
`"plugins"`
);
});
});
});
@@ -861,10 +861,10 @@ export default class PostgresSearchProvider extends BaseSearchProvider {
// spaces. Ref: https://github.com/caub/pg-tsquery/issues/27
quotedSearch ? limitedQuery.trim() : `${limitedQuery.trim()}*`
)
// Remove any trailing join characters
.replace(/&$/, "")
// Remove any trailing escape characters
.replace(/\\$/, "")
// Strip any trailing join (&) or escape (\) characters, in any
// combination, so we never hand to_tsquery an operator with no
// operand (e.g. a tail of "&\" would leave a dangling "&").
.replace(/[&\\]+$/, "")
);
}