fix: 5 bugs found during integration testing#8
Conversation
- auth: await assignRole/removeRole so the operation completes before returning, fixing empty stdout on role assign/remove (#1) - index: pass { type: 'sorted' } instead of { sorted: true } to js-doc-store createIndex, fixing --sorted flag being ignored (#2) - vec import: accept { exported, records } wrapper object from vec export, not just bare arrays (#3) - vec store-batch: read metadata from rec["metadata"] (with fallback to rec["meta"]) so JSONL metadata is preserved (#4) - aggregate $unwind: strip leading $ from field name before passing to js-doc-store unwind(), fixing arrays not being flattened (#5) Closes #1, #2, #3, #4, #5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request enhances database and vector command handlers by ensuring asynchronous role operations are awaited, refining the $unwind aggregation stage to handle leading $ prefixes, and updating index creation to specify types. It also improves batch operations by supporting a metadata field and allowing wrapped record arrays in imports. Feedback highlights the need to apply similar await fixes to the logout sub-command and suggests extending the $unwind logic to handle object-based path definitions.
| if (op === "assign") await auth.assignRole(targetUser, role); | ||
| else if (op === "remove") await auth.removeRole(targetUser, role); |
There was a problem hiding this comment.
Adding await here is correct as these operations are asynchronous and must complete before the handler returns to ensure the response is accurate and errors are caught.
Note that the same issue appears to exist in logoutSub (lines 136 and 138 in the full file), where auth.logoutAll() and auth.logout() are called without await. You should consider applying the same fix there to ensure consistent behavior and proper error handling during logout.
| case "$unwind": { | ||
| const unwindField = typeof arg === "string" && arg.startsWith("$") ? arg.slice(1) : arg; | ||
| pipe = pipe.unwind(unwindField as string); | ||
| break; | ||
| } |
There was a problem hiding this comment.
The fix for $unwind correctly handles the string shorthand by stripping the leading $. However, if the underlying library supports the object form of $unwind (e.g., {$unwind: { path: '$field', preserveNullAndEmptyArrays: true }}), this implementation will pass the object directly to pipe.unwind() with a string cast, and the leading $ inside the path property will remain.
If the object form is supported, you should also strip the $ from the path property within the object, similar to how it's handled in the $group stage (lines 214 and 233).
Summary
awaitadded toassignRole()/removeRole()— fixes empty stdout{ type: 'sorted' }tocreateIndex()instead of{ sorted: true }— fixes--sortedflag being ignoredimportOpnow accepts{ exported, records }wrapper fromexportOp, not just bare arraysrec["metadata"](withrec["meta"]fallback) instead of onlyrec["meta"]— fixes metadata loss in batch inserts$from field name before passing tojs-doc-storeunwind()— fixes arrays not being flattenedTest plan
tsupCloses #1, #2, #3, #4, #5
🤖 Generated with Claude Code