Implement the mongo_find tool with unit tests #140

Closed
opened 2026-08-31 22:05:00 +00:00 by david · 1 comment
Owner

Summary

Implement the mongo_find tool — query documents in a collection with an EJSON filter, projection, sort, and a default/capped limit, returned as Extended JSON — with unit tests against a fake client.

Background

Depends on: #137, #138, #139

Part of the read-only tool surface of the mongodb extension. The read-only boundary is enforced by construction: the tool calls only collection.find() — no write methods are ever imported or reachable. db and collection are required parameters. The extension never connects at load time (lazy client), so connection/auth failures surface here as categorized ToolErrors thrown from execute() (see src/errors.ts — the pi runtime requires throwing, not returning isError).

Documentation Required

A separate process downloads these into the listed folder before this issue is implemented. Check the folder for the actual reference material before starting.

docs/reference/mongodb-driver/ — for Collection.find, FindCursor.toArray, FindOptions, and EJSON:

Implementation Details

Create extensions/mongodb/src/tools/find.ts. Tool registered as mongo_find via pi.registerTool with a TypeBox parameter schema:

  • db (string, required) — database name
  • collection (string, required) — collection name
  • filter? (object) — query filter expressed in EJSON (e.g. {"_id": {"$oid": "..."}}); parsed with EJSON.parse so an ObjectId filter is actually queried as an ObjectId
  • projection? (object) — plain JSON inclusion/exclusion projection ({field: 1})
  • sort? (object) — plain JSON sort spec ({field: -1})
  • limit? (integer) — default 100, clamped to max 1000 via applyDefaultAndCap from src/defaults.ts

Behavior:

  1. EJSON.parse the filter (if provided; omit/{} when absent).
  2. const limit = applyDefaultAndCap(args.limit, FIND_LIMIT).
  3. const docs = await collection.find(filter, { projection, sort, limit }).toArray() — wrap in try/catch; on error toToolError(err, context) (throws).
  4. Serialize with ejsonSerializeWithTruncation(docs) from src/serialize.ts.
  5. Return the EJSON text as content and details: { docCount, truncated, limit }truncated is true when more documents existed than were returned.

Mirror the structure of the sibling extensions/postgres/src/tools/ implementations. Tests use a hand-rolled fake client exposing db(name){ collection(name) → { find(filter, options) → { toArray() }, ... } } returning canned BSON-shaped docs (including ObjectId/Date/Binary) — the same pattern postgres uses with registerDbTools(pi, pool).

Write co-located tests in src/tools/find.test.ts:

  • Happy path: fake client returns docs incl. ObjectId/Date/Binary → EJSON output ({"$oid": ...} etc.) and correct details.
  • ObjectId filter: pass filter: {"_id": {"$oid": "..."}} → the fake client receives a real ObjectId (assert via the fake's recorded arguments).
  • limit omitted → fake receives 100.
  • limit: 5000 → clamped to 1000.
  • Each error category (connection, auth, invalid, server, unexpected) surfaces as the categorized message.
  • Truncation: over-cap docs → marker in output, truncated: true.

Acceptance Criteria

  • Happy path returns EJSON array with BSON types preserved and correct details: { docCount, truncated, limit }.
  • An EJSON filter with $oid is passed to the driver as a real ObjectId.
  • limit omitted → default 100 used; limit above 1000 → clamped to 1000.
  • All five error categories throw categorized ToolErrors with correct message prefixes.
  • Over-cap results surface the truncation marker and truncated: true.
  • bun test in extensions/mongodb/ is green for src/tools/find.ts.

Test Plan

cd extensions/mongodb
bun test   # find tool tests green
## Summary Implement the `mongo_find` tool — query documents in a collection with an EJSON filter, projection, sort, and a default/capped limit, returned as Extended JSON — with unit tests against a fake client. ## Background **Depends on:** #137, #138, #139 Part of the read-only tool surface of the mongodb extension. The read-only boundary is enforced by construction: the tool calls only `collection.find()` — no write methods are ever imported or reachable. `db` and `collection` are required parameters. The extension never connects at load time (lazy client), so connection/auth failures surface here as categorized `ToolError`s thrown from `execute()` (see `src/errors.ts` — the pi runtime requires throwing, not returning `isError`). ## Documentation Required A separate process downloads these into the listed folder before this issue is implemented. Check the folder for the actual reference material before starting. **`docs/reference/mongodb-driver/`** — for `Collection.find`, `FindCursor.toArray`, `FindOptions`, and EJSON: - https://mongodb.github.io/node-mongodb-native/7.6/classes/Collection.html — API reference for `Collection`: `find(filter?, options?)` → `FindCursor`; `FindOptions` include `projection`, `sort`, `limit`. - https://mongodb.github.io/node-mongodb-native/7.6/ — TypeDoc API reference index (cursor class, option types). - https://www.mongodb.com/docs/drivers/node/current/data-formats/extended-json/ — EJSON guide: `EJSON.parse()` (accepts relaxed and canonical forms — this is how the `filter` param becomes real BSON types like ObjectId). - https://www.mongodb.com/docs/drivers/node/current/databases-collections/ — guide context: `db.collection(name)` → `Collection`. ## Implementation Details Create `extensions/mongodb/src/tools/find.ts`. Tool registered as `mongo_find` via `pi.registerTool` with a TypeBox parameter schema: - `db` (string, **required**) — database name - `collection` (string, **required**) — collection name - `filter?` (object) — query filter expressed in **EJSON** (e.g. `{"_id": {"$oid": "..."}}`); parsed with `EJSON.parse` so an ObjectId filter is actually queried as an ObjectId - `projection?` (object) — plain JSON inclusion/exclusion projection (`{field: 1}`) - `sort?` (object) — plain JSON sort spec (`{field: -1}`) - `limit?` (integer) — default 100, clamped to max 1000 via `applyDefaultAndCap` from `src/defaults.ts` Behavior: 1. `EJSON.parse` the filter (if provided; omit/`{}` when absent). 2. `const limit = applyDefaultAndCap(args.limit, FIND_LIMIT)`. 3. `const docs = await collection.find(filter, { projection, sort, limit }).toArray()` — wrap in try/catch; on error `toToolError(err, context)` (throws). 4. Serialize with `ejsonSerializeWithTruncation(docs)` from `src/serialize.ts`. 5. Return the EJSON text as content and `details: { docCount, truncated, limit }` — `truncated` is true when more documents existed than were returned. Mirror the structure of the sibling `extensions/postgres/src/tools/` implementations. Tests use a hand-rolled fake client exposing `db(name)` → `{ collection(name) → { find(filter, options) → { toArray() }, ... } }` returning canned BSON-shaped docs (including ObjectId/Date/Binary) — the same pattern postgres uses with `registerDbTools(pi, pool)`. Write co-located tests in `src/tools/find.test.ts`: - Happy path: fake client returns docs incl. ObjectId/Date/Binary → EJSON output (`{"$oid": ...}` etc.) and correct `details`. - ObjectId filter: pass `filter: {"_id": {"$oid": "..."}}` → the fake client receives a real ObjectId (assert via the fake's recorded arguments). - `limit` omitted → fake receives 100. - `limit: 5000` → clamped to 1000. - Each error category (connection, auth, invalid, server, unexpected) surfaces as the categorized message. - Truncation: over-cap docs → marker in output, `truncated: true`. ## Acceptance Criteria - [ ] Happy path returns EJSON array with BSON types preserved and correct `details: { docCount, truncated, limit }`. - [ ] An EJSON `filter` with `$oid` is passed to the driver as a real ObjectId. - [ ] `limit` omitted → default 100 used; `limit` above 1000 → clamped to 1000. - [ ] All five error categories throw categorized `ToolError`s with correct message prefixes. - [ ] Over-cap results surface the truncation marker and `truncated: true`. - [ ] `bun test` in `extensions/mongodb/` is green for `src/tools/find.ts`. ## Test Plan ```bash cd extensions/mongodb bun test # find tool tests green ```
david closed this issue 2026-09-01 00:19:12 +00:00
Author
Owner

pi-loop opened and merged a pull request for this issue: #157

pi-loop opened and merged a pull request for this issue: https://git.excelera.net/david/pi-extensions-and-skills/pulls/157
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
david/pi-extensions-and-skills#140
No description provided.