Skip to content

feat(query): add shared query base classes#25

Open
nkanu17 wants to merge 1 commit into
mainfrom
stack/query-core-on-hybrid
Open

feat(query): add shared query base classes#25
nkanu17 wants to merge 1 commit into
mainfrom
stack/query-core-on-hybrid

Conversation

@nkanu17
Copy link
Copy Markdown
Contributor

@nkanu17 nkanu17 commented May 13, 2026

Summary

This PR adds the shared query foundation needed for the remaining RedisVL Python parity work.

  • Adds BaseQuery for common FT.SEARCH query state and validation.
  • Adds BaseVectorQuery for vector-specific state, datatype normalization, and shared vector validation.
  • Moves VectorQuery, VectorRangeQuery, FilterQuery, CountQuery, and TextQuery onto the shared base classes without changing their constructor-facing APIs.
  • Adds chainable query helpers:
    • setFilter(...)
    • setReturnFields(...)
    • paging(...)
    • sortBy(...)
  • Wires query-level sortBy() through SearchIndex.search().

Stacking

This PR is stacked on top of #9 (feat/hybrid-search).

Do not merge this PR before #9 lands.

TDD Notes

Tests were written first and failed before implementation:

  • tests/unit/query/base.test.ts
    • BaseQuery common config, filter updates, return fields, skip-decode fields, paging, sorting, and validation.
    • BaseVectorQuery vector state, datatype normalization, defensive copying, and validation.
  • tests/unit/query/vector.test.ts
    • VectorQuery inheritance from BaseVectorQuery / BaseQuery.
    • Chainable paging, setReturnFields, and setFilter behavior.
  • tests/unit/indexes/search-index.test.ts
    • Query-level sortBy() reaches FT.SEARCH options.

Implementation followed after the failing tests were in place.

Verification

  • npm run type-check
  • npm run test:unit
  • npm run format:check -- src/query/base.ts src/query/vector.ts src/query/range.ts src/query/filter-query.ts src/query/count.ts src/query/text.ts src/indexes/search-index.ts tests/unit/query/base.test.ts tests/unit/query/vector.test.ts tests/unit/indexes/search-index.test.ts
  • npm run build
  • REDISVL_SKIP_HYBRID=true npm test -- tests/integration

@nkanu17
Copy link
Copy Markdown
Contributor Author

nkanu17 commented May 13, 2026

Closing this for now. This stacked Query Core branch should only become a PR if/when we explicitly decide to add new scope on top of #9.

@nkanu17 nkanu17 closed this May 13, 2026
@nkanu17 nkanu17 reopened this May 13, 2026
@nkanu17
Copy link
Copy Markdown
Contributor Author

nkanu17 commented May 13, 2026

PR Notes\n\nReopened this as the next feature branch stacked on #9.\n\n- Base branch: \n- Head branch: \n- Scope: shared query foundation only\n\nThis should stay blocked on #9 landing first.

@nkanu17
Copy link
Copy Markdown
Contributor Author

nkanu17 commented May 13, 2026

PR Notes

Reopened this as the next feature branch stacked on #9.

  • Base branch: feat/hybrid-search
  • Head branch: stack/query-core-on-hybrid
  • Scope: shared query foundation only

This should stay blocked on #9 landing first.

Base automatically changed from feat/hybrid-search to main May 22, 2026 20:11
@banker
Copy link
Copy Markdown
Contributor

banker commented May 22, 2026

Thanks @nkanu17 — the BaseQuery / BaseVectorQuery design and the chainable helpers look great, and the test coverage is solid. A few items before merge:

1. Rebase onto current main

mergeable: CONFLICTINGfeat/hybrid-search (#9), feat/aggregation-query-v2 (#28), and feat/redis-client-resp2-guard (#29) have all landed on main since this branch opened, so a rebase is needed.

2. Migrate HybridQuery and AggregationQuery onto BaseQuery in this PR

Both classes landed on main after this PR was opened, and neither extends BaseQuery:

  • src/query/hybrid.ts:245export class HybridQuery {
  • src/query/aggregation.ts:227export class AggregationQuery {

If they don't get migrated here, we ship main with split inheritance (5 query types on BaseQuery, 2 not) and a follow-up is guaranteed. I'd much rather they ride along with this PR than leave a known cleanup behind — please fold them in.

AggregationQuery is the easier of the two (FT.AGGREGATE doesn't share all of FT.SEARCH's state, so it may only inherit the filter/returnFields surface — feel free to push back if it doesn't fit cleanly). HybridQuery should be a natural fit since FT.HYBRID is closer to FT.SEARCH semantics.

3. Document sortBy precedence

SearchIndex.search() now sets SORTBY from query.sortFields[0], then overwrites it from options.sortBy if both are supplied. That's a reasonable choice (preserves the existing search() signature), but it needs to be documented on the SearchIndex.search JSDoc so callers know which wins. Worth a comment on the searchOptions.SORTBY assignment too.

4. Note the interface→class change in the PR body

Converting BaseQuery from an exported interface to an exported abstract class is technically a breaking change for anyone implementing the interface externally. At v0.1.0-beta this is fine, but please add a one-line note in the PR description so it ends up in the release notes when we cut the next version.

Re-review once #2 is in. Heads up that #31 (TextQuery stopwords) will likely land first — I've told that author they won't need to rebase against this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants