HarperFast / HarperFast/harper

Use an options object for searchByIndex and the custom-index search() contract

Open
#2,165 5 comments 0 reactions 0 assignees View on GitHub
area:search enhancement
Dominant language
JavaScript
Stars
89
Forks
10
Avg merge
2d 6h
Merged PRs (30d)
200

Description

`searchByIndex` in `resources/search.ts` has grown to eight positional parameters, the last of
which — `minResults` — was added in [#2125](https://github.com/HarperFast/harper/pull/2125) so a
query's `offset + limit` could reach an approximate index and stop it from silently truncating the
result set.

```ts
export function searchByIndex(
searchCondition: DirectCondition,
transaction: any,
reverse: boolean,
Table: any,
allowFullScan?: boolean,
filtered?: any,
context?: any,
minResults?: number
): AsyncIterable;
```

Five of those eight are optional, so most call sites pass a run of `undefined`s or stop early and
inherit defaults they never meant to choose. `resources/Table.ts` and the recursive relationship
calls inside `search.ts` pass nothing past `filtered`, which is harmless today only because none of
them lead with a vector sort.

The real cost is on the custom-index contract. `HierarchicalNavigableSmallWorld.search()` is the
in-tree implementation of an interface an external index can also implement, and its signature grew
the same way — `(searchCondition, context, filter?, minResults?)`. Every future capability that has
to reach an approximate index (a cursor for stable paging, a deadline, a recall target) is another
positional argument, and adding one is a breaking change for any index implemented outside this
repo. The contract is still unreleased, so reshaping it is cheap now and expensive later.

## Suggested shape

Collapse the optional tail into an options object on both sides:

```ts
searchByIndex(searchCondition, transaction, reverse, Table, {
allowFullScan,
filtered,
context,
minResults,
});

customIndex.search(searchCondition, context, { filter, minResults });
```

The four leading parameters are required at every call site and read fine positionally; it is the
optional tail that should become named. Whether the custom-index `search()` keeps `context`
positional is a judgment call — it is passed by every caller, so either works.

Worth deciding as part of this: whether the options object is also where a future paging cursor
lands, since #2125 documented `offset`/`limit` over an approximate index as best-effort rather than
a stable partition (see the "An approximate index returns at most `ef` rows" section in `DESIGN.md`).

## Scope

- `resources/search.ts` — `searchByIndex` signature, the two recursive call sites, and the
`customIndex.search()` call.
- `resources/Table.ts:4960` — call site.
- `resources/indexes/HierarchicalNavigableSmallWorld.ts` — `search()` signature.
- Custom-index documentation, if the contract is written down anywhere outside the code.

Mechanical; no behaviour change intended. Raised by @maurice-harper in review of #2125 and recorded
as item 6 of that PR's "For the human reviewer" section, where the positional argument was kept to
avoid reshaping the contract inside a correctness fix.

Contributor guide

Open the contributing guide

Research direction

Start in resources/search.ts at searchByIndex, its recursive calls, and the customIndex.search() call; then inspect resources/Table.ts:4960 and the search() signature in resources/indexes/HierarchicalNavigableSmallWorld.ts. Check the approximate-index guidance in DESIGN.md and any custom-index documentation. Done means the optional arguments use named options at all listed call sites and the search behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
backend, databases
Issue type
Refactor
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.