-
Notifications
You must be signed in to change notification settings - Fork 0
refactor(gomongo): return native Go types instead of JSON strings #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Change Result type from returning JSON strings to native Go types for
better type safety and usability.
Key changes:
- Add types.OperationType enum in new types/ package (single source of truth)
- Result.Value is now []any containing native Go types (bson.D, string,
int64, bool) instead of JSON-encoded strings
- Result.Operation indicates the operation type for callers to determine
expected element types in Value slice
Return types by operation:
- Find/Aggregate/GetIndexes/GetCollectionInfos: []bson.D
- FindOne/FindOneAnd*: 0 or 1 bson.D
- CountDocuments/EstimatedDocumentCount: int64
- Distinct: values of various types
- ShowDatabases/ShowCollections/GetCollectionNames: strings
- Write operations: bson.D with operation result
- Admin operations: bson.D with {ok: 1} or bool/string
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Refactors gomongo execution results to return native Go/BSON values (instead of Extended JSON strings) and introduces a shared types.OperationType enum to make result typing explicit.
Changes:
- Replace
Result.Rows/RowCountwithResult.Operation+Result.Value []anyacross public API, executor, and tests. - Add
types.OperationTypeas the shared operation enum and update translator/executor to use it. - Update README and test suite to assert on native Go types (e.g.,
bson.D,int64,string,bool).
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| write_test.go | Updates write-operation tests to assert against Result.Value and BSON-native values. |
| unicode_test.go | Updates unicode tests to assert against BSON-native values rather than JSON strings. |
| types/operation_type.go | Adds shared types.OperationType enum as a single source of truth. |
| internal/translator/visitor.go | Switches parsed operation type assignment to types.OperationType. |
| internal/translator/types.go | Updates translator.Operation.OpType to use types.OperationType. |
| internal/translator/bson_helpers_test.go | Updates helper tests to validate typed BSON values in Result.Value. |
| internal/testutil/container_test.go | Adjusts test expectations to use len(result.Value) instead of RowCount. |
| internal/executor/write.go | Returns write results as BSON-native documents with Operation set. |
| internal/executor/server.go | Returns show-databases results as []string in Value. |
| internal/executor/executor.go | Refactors internal executor Result and dispatch to use types.OperationType. |
| internal/executor/database.go | Refactors show/get collection operations to return native types. |
| internal/executor/collection.go | Refactors find/aggregate/distinct/count/indexes paths to return native types. |
| internal/executor/admin.go | Refactors admin operation results to native types (string/bool/bson.D). |
| executor.go | Wires public gomongo.Result to internal executor result shape. |
| database_test.go | Updates DB-level tests to validate Result.Value typing/contents. |
| collection_test.go | Adds helpers for converting Value elements to JSON for string-based assertions; updates many tests. |
| client.go | Updates public Result shape and documents expected element types by operation. |
| admin_test.go | Updates admin tests to check native values and simplifies helpers. |
| README.md | Updates docs/examples to explain and demonstrate Result.Operation + Result.Value. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
internal/executor/collection.go
Outdated
| var docs []bson.D | ||
| for cursor.Next(ctx) { | ||
| var doc bson.M | ||
| var doc bson.D | ||
| if err := cursor.Decode(&doc); err != nil { | ||
| return nil, fmt.Errorf("decode failed: %w", err) | ||
| } | ||
|
|
||
| // Marshal to Extended JSON (Relaxed) | ||
| jsonBytes, err := bson.MarshalExtJSONIndent(doc, false, false, "", " ") | ||
| if err != nil { | ||
| return nil, fmt.Errorf("marshal failed: %w", err) | ||
| } | ||
| rows = append(rows, string(jsonBytes)) | ||
| docs = append(docs, doc) | ||
| } | ||
|
|
||
| if err := cursor.Err(); err != nil { | ||
| return nil, fmt.Errorf("cursor error: %w", err) | ||
| } | ||
|
|
||
| // Convert []bson.D to []any | ||
| values := make([]any, len(docs)) | ||
| for i, doc := range docs { | ||
| values[i] = doc | ||
| } |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
executeFind currently collects results into a []bson.D and then allocates/copies into a []any. This adds an extra allocation and full slice copy for large result sets. You can append decoded documents directly into a []any (or preallocate the []any when you can estimate size) to avoid the intermediate slice.
README.md
Outdated
| doc := val.(bson.D) | ||
| fmt.Printf("%+v\n", doc) | ||
| } | ||
|
|
||
| // For countDocuments(), single element is int64 | ||
| countResult, _ := gc.Execute(ctx, "mydb", `db.users.countDocuments({})`) | ||
| count := countResult.Value[0].(int64) |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The README usage snippet uses unchecked type assertions (val.(bson.D) and countResult.Value[0].(int64)). This can panic if the statement changes or an error path returns a different shape. Since README code is often copied verbatim, it would be safer to show checked assertions (", ok := ...") and basic error handling for the countResult call.
| doc := val.(bson.D) | |
| fmt.Printf("%+v\n", doc) | |
| } | |
| // For countDocuments(), single element is int64 | |
| countResult, _ := gc.Execute(ctx, "mydb", `db.users.countDocuments({})`) | |
| count := countResult.Value[0].(int64) | |
| doc, ok := val.(bson.D) | |
| if !ok { | |
| log.Printf("unexpected document type %T\n", val) | |
| continue | |
| } | |
| fmt.Printf("%+v\n", doc) | |
| } | |
| // For countDocuments(), single element is int64 | |
| countResult, err := gc.Execute(ctx, "mydb", `db.users.countDocuments({})`) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| if len(countResult.Value) == 0 { | |
| log.Fatal("no count result returned") | |
| } | |
| count, ok := countResult.Value[0].(int64) | |
| if !ok { | |
| log.Fatalf("unexpected count type %T\n", countResult.Value[0]) | |
| } |
| // containsDatabaseName checks if the values contain the given database name. | ||
| // Values can be strings (from show dbs) or bson.D documents. | ||
| func containsDatabaseName(values []any, name string) bool { |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment above containsDatabaseName says values can be strings or bson.D documents, but the implementation only checks for string values. Either update the comment to match the actual behavior (show dbs returns strings) or add bson.D handling for consistency with containsCollectionName.
| // These tests verify BSON helper function conversions through the full pipeline. | ||
| // Since the helper functions are not exported, we test them end-to-end. | ||
|
|
||
| // getDocField extracts a string representation of a field from a bson.D document |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The getDocField doc comment is inaccurate: it says it "extracts a string representation" but the function returns the field's value as any. Please update the comment to reflect what the helper actually returns (e.g., "extracts the value of a field from a bson.D").
| // getDocField extracts a string representation of a field from a bson.D document | |
| // getDocField extracts the value of a field from a bson.D document. |
write_test.go
Outdated
| func valueToJSONWrite(v any) string { | ||
| bytes, err := bson.MarshalExtJSONIndent(v, false, false, "", " ") | ||
| if err != nil { | ||
| return fmt.Sprintf("%v", v) | ||
| } | ||
| return string(bytes) | ||
| } |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
write_test.go introduces valueToJSONWrite, but the repo already has an equivalent helper (valueToJSON / valuesToStrings) in collection_test.go within the same gomongo_test package. This duplication makes it easier for helpers to drift and increases maintenance cost. Consider reusing the existing helper (or moving a single helper into a shared *_test.go/util file under internal/testutil) and removing this per-file variant.
unicode_test.go
Outdated
| func valueToJSONUnicode(v any) string { | ||
| bytes, err := bson.MarshalExtJSONIndent(v, false, false, "", " ") | ||
| if err != nil { | ||
| return fmt.Sprintf("%v", v) | ||
| } | ||
| return string(bytes) | ||
| } |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unicode_test.go adds valueToJSONUnicode, which is functionally the same as the existing valueToJSON helper in collection_test.go (same package). Duplicating these helpers across test files increases maintenance overhead. Prefer reusing the existing helper (or centralizing a single helper in a shared test util file) and deleting this per-file copy.
- Optimize executeFind to append directly to []any, avoiding intermediate slice - Use checked type assertions in README examples for safer error handling - Fix misleading comment on containsDatabaseName (values are always strings) - Fix misleading comment on getDocField helper in tests - Consolidate duplicate valueToJSON test helpers into single shared function
Summary
types.OperationTypeenum in newtypes/package as single source of truthResult.Valueis now[]anycontaining native Go types (bson.D,string,int64,bool)Result.Operationindicates the operation type for type assertionsReturn Types by Operation
[]bson.Dbson.Dint64stringbson.Dwith operation resultbson.Dwith{ok: 1},bool, orstringTest Plan
🤖 Generated with Claude Code