diff --git a/errors.go b/errors.go index 47579b5..34b3cd4 100644 --- a/errors.go +++ b/errors.go @@ -19,24 +19,21 @@ func (e *ParseError) Error() string { } // UnsupportedOperationError represents an unsupported operation. +// This is returned for operations that are not planned for implementation. type UnsupportedOperationError struct { Operation string - Hint string } func (e *UnsupportedOperationError) Error() string { - if e.Hint != "" { - return fmt.Sprintf("unsupported operation %q: %s", e.Operation, e.Hint) - } - return fmt.Sprintf("unsupported operation %q", e.Operation) + return fmt.Sprintf("unsupported operation: %s", e.Operation) } -// DeprecatedOperationError represents a deprecated operation with alternatives. -type DeprecatedOperationError struct { - Operation string - Alternative string +// PlannedOperationError represents an operation that is planned but not yet implemented. +// When the caller receives this error, it should fallback to mongosh. +type PlannedOperationError struct { + Operation string } -func (e *DeprecatedOperationError) Error() string { - return fmt.Sprintf("%s is deprecated. Use %s instead", e.Operation, e.Alternative) +func (e *PlannedOperationError) Error() string { + return fmt.Sprintf("operation %s is not yet implemented", e.Operation) } diff --git a/executor.go b/executor.go index f403b09..ee1538d 100644 --- a/executor.go +++ b/executor.go @@ -85,7 +85,6 @@ func executeOperation(ctx context.Context, client *mongo.Client, database string default: return nil, &UnsupportedOperationError{ Operation: statement, - Hint: "could not determine operation type", } } } diff --git a/executor_test.go b/executor_test.go index 8487844..b469618 100644 --- a/executor_test.go +++ b/executor_test.go @@ -284,48 +284,46 @@ func TestParseError(t *testing.T) { require.ErrorAs(t, err, &parseErr) } -func TestUnsupportedOperation(t *testing.T) { +func TestPlannedOperation(t *testing.T) { client, cleanup := setupTestContainer(t) defer cleanup() gc := gomongo.NewClient(client) ctx := context.Background() + // insertOne is a planned M2 operation - should return PlannedOperationError _, err := gc.Execute(ctx, "testdb", "db.users.insertOne({ name: 'test' })") require.Error(t, err) - var unsupportedErr *gomongo.UnsupportedOperationError - require.ErrorAs(t, err, &unsupportedErr) - require.Equal(t, "insertOne()", unsupportedErr.Operation) + var plannedErr *gomongo.PlannedOperationError + require.ErrorAs(t, err, &plannedErr) + require.Equal(t, "insertOne()", plannedErr.Operation) } -func TestUnsupportedAtlasSearchIndex(t *testing.T) { +func TestUnsupportedOperation(t *testing.T) { client, cleanup := setupTestContainer(t) defer cleanup() gc := gomongo.NewClient(client) ctx := context.Background() - // Test createSearchIndex + // createSearchIndex is NOT in the registry - should return UnsupportedOperationError _, err := gc.Execute(ctx, "testdb", `db.movies.createSearchIndex({ name: "default", definition: { mappings: { dynamic: true } } })`) require.Error(t, err) var unsupportedErr *gomongo.UnsupportedOperationError require.ErrorAs(t, err, &unsupportedErr) require.Equal(t, "createSearchIndex()", unsupportedErr.Operation) - require.Contains(t, unsupportedErr.Hint, "Atlas Search Index") } func TestMethodRegistryStats(t *testing.T) { - total, deprecated, unsupported := gomongo.MethodRegistryStats() + total := gomongo.MethodRegistryStats() - // Verify we have a reasonable number of methods registered - require.GreaterOrEqual(t, total, 100, "expected at least 100 methods in registry") - require.GreaterOrEqual(t, deprecated, 20, "expected at least 20 deprecated methods") - require.GreaterOrEqual(t, unsupported, 80, "expected at least 80 unsupported methods") + // Registry should contain M2 (10) + M3 (22) = 32 planned methods + require.Equal(t, 32, total, "expected 32 planned methods in registry (M2: 10, M3: 22)") // Log stats for visibility - t.Logf("Method Registry Stats: total=%d, deprecated=%d, unsupported=%d", total, deprecated, unsupported) + t.Logf("Method Registry Stats: total=%d planned methods", total) } func TestFindWithFilter(t *testing.T) { @@ -1914,7 +1912,7 @@ func TestDistinctNumericValues(t *testing.T) { require.Equal(t, 3, result.RowCount) // 100, 85, 90 } -func TestCursorCountDeprecated(t *testing.T) { +func TestCursorCountUnsupported(t *testing.T) { client, cleanup := setupTestContainer(t) defer cleanup() @@ -1922,10 +1920,11 @@ func TestCursorCountDeprecated(t *testing.T) { gc := gomongo.NewClient(client) - // cursor.count() is deprecated and should return an error + // cursor.count() is not in the planned registry, should return UnsupportedOperationError _, err := gc.Execute(ctx, "testdb", "db.users.find().count()") require.Error(t, err) - require.Contains(t, err.Error(), "count()") - require.Contains(t, err.Error(), "countDocuments()") - require.Contains(t, err.Error(), "estimatedDocumentCount()") + + var unsupportedErr *gomongo.UnsupportedOperationError + require.ErrorAs(t, err, &unsupportedErr) + require.Equal(t, "count()", unsupportedErr.Operation) } diff --git a/go.mod b/go.mod index 0dcc4e9..937fe5a 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.5 require ( github.com/antlr4-go/antlr/v4 v4.13.1 - github.com/bytebase/parser v0.0.0-20260120080341-a57d4b68030c + github.com/bytebase/parser v0.0.0-20260121030202-698704919f24 github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go/modules/mongodb v0.40.0 diff --git a/go.sum b/go.sum index 6623903..72fbf63 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/bytebase/antlr/v4 v4.0.0-20240827034948-8c385f108920 h1:IfmPt5o5R70NKtOrs+QHOoCgViYZelZysGxVBvV4ybA= github.com/bytebase/antlr/v4 v4.0.0-20240827034948-8c385f108920/go.mod h1:ykhjIPiv0IWpu3OGXCHdz2eUSe8UNGGD6baqjs8jSuU= -github.com/bytebase/parser v0.0.0-20260120080341-a57d4b68030c h1:owIVaPTU4DrzzajK0BsuyRtScB/8JNQco7bzg4ZduLA= -github.com/bytebase/parser v0.0.0-20260120080341-a57d4b68030c/go.mod h1:jeak/EfutSOAuWKvrFIT2IZunhWprM7oTFBRgZ9RCxo= +github.com/bytebase/parser v0.0.0-20260121030202-698704919f24 h1:oonTO26orUa4bYk/hQjALiYO1zII+Kzpjg75OnC3VtU= +github.com/bytebase/parser v0.0.0-20260121030202-698704919f24/go.mod h1:jeak/EfutSOAuWKvrFIT2IZunhWprM7oTFBRgZ9RCxo= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= diff --git a/method_registry.go b/method_registry.go index 988aeaa..53eefde 100644 --- a/method_registry.go +++ b/method_registry.go @@ -4,1662 +4,87 @@ package gomongo type methodStatus int const ( - statusSupported methodStatus = iota - statusDeprecated - statusUnsupported -) - -// methodContext distinguishes where a method can be called. -type methodContext int - -const ( - contextCollection methodContext = iota - contextCursor - contextDatabase - contextConnection // Mongo(), connect(), connection methods - contextReplication // rs.* methods - contextSharding // sh.* methods - contextEncryption // KeyVault, ClientEncryption methods - contextBulk // Bulk operation methods - contextPlanCache // PlanCache methods - contextStream // sp.* stream processing methods - contextNative // Native shell functions like cat(), load(), quit() + // statusPlanned means the method is planned for implementation (M2/M3). + // When encountered, the caller should fallback to mongosh. + statusPlanned methodStatus = iota ) // methodInfo contains metadata about a MongoDB method. type methodInfo struct { - status methodStatus - context methodContext - alternative string // for deprecated methods: what to use instead - hint string // additional guidance for unsupported methods + status methodStatus } -// methodRegistry maps method names to their metadata. -// Key format: "methodName" for unique methods, or "context:methodName" for context-specific methods. -// When looking up, first try context-specific key, then fall back to generic key. +// methodRegistry contains only methods we plan to implement (M2, M3). +// If a method is NOT in this registry, it's unsupported (throw error, no fallback). +// If a method IS in this registry, it's planned (fallback to mongosh). var methodRegistry = map[string]methodInfo{ // ============================================================ - // DEPRECATED METHODS - These have alternatives users should use + // MILESTONE 2: Write Operations (10 methods) // ============================================================ - // Collection methods (deprecated) - "collection:count": { - status: statusDeprecated, - context: contextCollection, - alternative: "countDocuments() or estimatedDocumentCount()", - }, - "collection:insert": { - status: statusDeprecated, - context: contextCollection, - alternative: "insertOne() or insertMany()", - }, - "collection:update": { - status: statusDeprecated, - context: contextCollection, - alternative: "updateOne(), updateMany(), or replaceOne()", - }, - "collection:remove": { - status: statusDeprecated, - context: contextCollection, - alternative: "deleteOne() or deleteMany()", - }, - "collection:save": { - status: statusDeprecated, - context: contextCollection, - alternative: "insertOne() or replaceOne() with upsert option", - }, - "collection:findAndModify": { - status: statusDeprecated, - context: contextCollection, - alternative: "findOneAndUpdate(), findOneAndReplace(), or findOneAndDelete()", - }, - "collection:ensureIndex": { - status: statusDeprecated, - context: contextCollection, - alternative: "createIndex()", - }, - "collection:reIndex": { - status: statusDeprecated, - context: contextCollection, - alternative: "drop and recreate indexes, or use the reIndex database command", - }, - "collection:dropIndex": { - status: statusDeprecated, - context: contextCollection, - alternative: "dropIndexes()", - }, - "collection:copyTo": { - status: statusDeprecated, - context: contextCollection, - alternative: "aggregation with $out or $merge stage", - }, - "collection:group": { - status: statusDeprecated, - context: contextCollection, - alternative: "aggregate() with $group stage", - }, - - // Cursor methods (deprecated) - "cursor:count": { - status: statusDeprecated, - context: contextCursor, - alternative: "countDocuments() or estimatedDocumentCount()", - }, - "cursor:forEach": { - status: statusDeprecated, - context: contextCursor, - alternative: "for await...of syntax or toArray()", - }, - "cursor:snapshot": { - status: statusDeprecated, - context: contextCursor, - alternative: "hint() with _id index", - }, - "cursor:maxScan": { - status: statusDeprecated, - context: contextCursor, - alternative: "maxTimeMS()", - }, - "cursor:addOption": { - status: statusDeprecated, - context: contextCursor, - alternative: "specific cursor methods like noCursorTimeout(), tailable(), etc.", - }, - - // Database methods (deprecated) - "database:addUser": { - status: statusDeprecated, - context: contextDatabase, - alternative: "createUser()", - }, - "database:removeUser": { - status: statusDeprecated, - context: contextDatabase, - alternative: "dropUser()", - }, - "database:eval": { - status: statusDeprecated, - context: contextDatabase, - alternative: "aggregation framework or application-side logic", - }, - "database:copyDatabase": { - status: statusDeprecated, - context: contextDatabase, - alternative: "mongodump and mongorestore", - }, - "database:cloneDatabase": { - status: statusDeprecated, - context: contextDatabase, - alternative: "mongodump and mongorestore", - }, - "database:cloneCollection": { - status: statusDeprecated, - context: contextDatabase, - alternative: "aggregation with $out or $merge stage", - }, - - // ============================================================ - // UNSUPPORTED METHODS - Not yet implemented but recognized - // ============================================================ - - // Write operations (unsupported - read-only for now) - "collection:insertOne": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:insertMany": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:updateOne": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:updateMany": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:deleteOne": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:deleteMany": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:replaceOne": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:findOneAndUpdate": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:findOneAndReplace": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:findOneAndDelete": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - "collection:bulkWrite": { - status: statusUnsupported, - context: contextCollection, - hint: "write operations are not supported yet", - }, - - // Index management (unsupported) - "collection:createIndex": { - status: statusUnsupported, - context: contextCollection, - hint: "index management operations are not supported yet", - }, - "collection:createIndexes": { - status: statusUnsupported, - context: contextCollection, - hint: "index management operations are not supported yet", - }, - "collection:dropIndexes": { - status: statusUnsupported, - context: contextCollection, - hint: "index management operations are not supported yet", - }, - - // Collection management (unsupported) - "collection:drop": { - status: statusUnsupported, - context: contextCollection, - hint: "collection management operations are not supported yet", - }, - "collection:renameCollection": { - status: statusUnsupported, - context: contextCollection, - hint: "collection management operations are not supported yet", - }, - - // Collection stats (unsupported) - "collection:stats": { - status: statusUnsupported, - context: contextCollection, - hint: "stats operations are not supported yet", - }, - "collection:storageSize": { - status: statusUnsupported, - context: contextCollection, - hint: "stats operations are not supported yet", - }, - "collection:totalIndexSize": { - status: statusUnsupported, - context: contextCollection, - hint: "stats operations are not supported yet", - }, - "collection:totalSize": { - status: statusUnsupported, - context: contextCollection, - hint: "stats operations are not supported yet", - }, - "collection:dataSize": { - status: statusUnsupported, - context: contextCollection, - hint: "stats operations are not supported yet", - }, - "collection:isCapped": { - status: statusUnsupported, - context: contextCollection, - hint: "stats operations are not supported yet", - }, - "collection:validate": { - status: statusUnsupported, - context: contextCollection, - hint: "validation operations are not supported yet", - }, - "collection:latencyStats": { - status: statusUnsupported, - context: contextCollection, - hint: "stats operations are not supported yet", - }, + // Insert Commands (2) + "collection:insertOne": {status: statusPlanned}, + "collection:insertMany": {status: statusPlanned}, - // Cursor terminal methods (unsupported) - "cursor:toArray": { - status: statusUnsupported, - context: contextCursor, - hint: "use find() or findOne() directly to get results", - }, - "cursor:next": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor iteration is not supported; use find() to get all results", - }, - "cursor:tryNext": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor iteration is not supported; use find() to get all results", - }, - "cursor:hasNext": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor iteration is not supported; use find() to get all results", - }, - "cursor:close": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor management is handled automatically", - }, - "cursor:isClosed": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor management is handled automatically", - }, - "cursor:isExhausted": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor management is handled automatically", - }, - "cursor:objsLeftInBatch": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor batch management is not supported", - }, - "cursor:itcount": { - status: statusUnsupported, - context: contextCursor, - hint: "use countDocuments() instead", - }, - "cursor:size": { - status: statusUnsupported, - context: contextCursor, - hint: "use countDocuments() instead", - }, - "cursor:explain": { - status: statusUnsupported, - context: contextCursor, - hint: "explain is not supported yet", - }, - "cursor:pretty": { - status: statusUnsupported, - context: contextCursor, - hint: "output is already formatted as JSON", - }, - "cursor:map": { - status: statusUnsupported, - context: contextCursor, - hint: "use aggregation $project stage for transformations", - }, + // Update Commands (3) + "collection:updateOne": {status: statusPlanned}, + "collection:updateMany": {status: statusPlanned}, + "collection:replaceOne": {status: statusPlanned}, - // Cursor modifier methods (unsupported) - "cursor:batchSize": { - status: statusUnsupported, - context: contextCursor, - hint: "batch size configuration is not supported yet", - }, - "cursor:collation": { - status: statusUnsupported, - context: contextCursor, - hint: "collation is not supported yet", - }, - "cursor:comment": { - status: statusUnsupported, - context: contextCursor, - hint: "query comments are not supported yet", - }, - "cursor:hint": { - status: statusUnsupported, - context: contextCursor, - hint: "index hints are not supported yet for find operations", - }, - "cursor:max": { - status: statusUnsupported, - context: contextCursor, - hint: "index bounds are not supported yet", - }, - "cursor:min": { - status: statusUnsupported, - context: contextCursor, - hint: "index bounds are not supported yet", - }, - "cursor:maxTimeMS": { - status: statusUnsupported, - context: contextCursor, - hint: "query timeout is not supported yet", - }, - "cursor:maxAwaitTimeMS": { - status: statusUnsupported, - context: contextCursor, - hint: "await timeout is not supported yet", - }, - "cursor:noCursorTimeout": { - status: statusUnsupported, - context: contextCursor, - hint: "cursor timeout configuration is not supported yet", - }, - "cursor:readConcern": { - status: statusUnsupported, - context: contextCursor, - hint: "read concern is not supported yet", - }, - "cursor:readPref": { - status: statusUnsupported, - context: contextCursor, - hint: "read preference is not supported yet", - }, - "cursor:returnKey": { - status: statusUnsupported, - context: contextCursor, - hint: "returnKey is not supported yet", - }, - "cursor:showRecordId": { - status: statusUnsupported, - context: contextCursor, - hint: "showRecordId is not supported yet", - }, - "cursor:tailable": { - status: statusUnsupported, - context: contextCursor, - hint: "tailable cursors are not supported yet", - }, - "cursor:allowDiskUse": { - status: statusUnsupported, - context: contextCursor, - hint: "allowDiskUse is not supported yet", - }, + // Delete Commands (2) + "collection:deleteOne": {status: statusPlanned}, + "collection:deleteMany": {status: statusPlanned}, - // Database methods (unsupported) - "database:createCollection": { - status: statusUnsupported, - context: contextDatabase, - hint: "database management operations are not supported yet", - }, - "database:dropDatabase": { - status: statusUnsupported, - context: contextDatabase, - hint: "database management operations are not supported yet", - }, - "database:stats": { - status: statusUnsupported, - context: contextDatabase, - hint: "stats operations are not supported yet", - }, - "database:serverStatus": { - status: statusUnsupported, - context: contextDatabase, - hint: "server status is not supported yet", - }, - "database:serverBuildInfo": { - status: statusUnsupported, - context: contextDatabase, - hint: "server info is not supported yet", - }, - "database:version": { - status: statusUnsupported, - context: contextDatabase, - hint: "version info is not supported yet", - }, - "database:hostInfo": { - status: statusUnsupported, - context: contextDatabase, - hint: "host info is not supported yet", - }, - "database:listCommands": { - status: statusUnsupported, - context: contextDatabase, - hint: "command listing is not supported yet", - }, - "database:runCommand": { - status: statusUnsupported, - context: contextDatabase, - hint: "raw command execution is not supported yet", - }, - "database:adminCommand": { - status: statusUnsupported, - context: contextDatabase, - hint: "admin commands are not supported yet", - }, - "database:getName": { - status: statusUnsupported, - context: contextDatabase, - hint: "database info is not supported yet", - }, - "database:getMongo": { - status: statusUnsupported, - context: contextDatabase, - hint: "connection management is not supported yet", - }, - "database:getSiblingDB": { - status: statusUnsupported, - context: contextDatabase, - hint: "database switching is not supported yet", - }, - - // User management (unsupported) - "database:createUser": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:dropUser": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:auth": { - status: statusUnsupported, - context: contextDatabase, - hint: "authentication is handled at connection level", - }, - - // Atlas Search Index methods (unsupported) - "collection:createSearchIndex": { - status: statusUnsupported, - context: contextCollection, - hint: "Atlas Search Index operations are not supported yet", - }, - "collection:createSearchIndexes": { - status: statusUnsupported, - context: contextCollection, - hint: "Atlas Search Index operations are not supported yet", - }, - "collection:dropSearchIndex": { - status: statusUnsupported, - context: contextCollection, - hint: "Atlas Search Index operations are not supported yet", - }, - "collection:updateSearchIndex": { - status: statusUnsupported, - context: contextCollection, - hint: "Atlas Search Index operations are not supported yet", - }, - "collection:getSearchIndexes": { - status: statusUnsupported, - context: contextCollection, - hint: "Atlas Search Index operations are not supported yet", - }, - - // Watch/Change Stream methods (unsupported) - "collection:watch": { - status: statusUnsupported, - context: contextCollection, - hint: "change stream operations are not supported yet", - }, - "database:watch": { - status: statusUnsupported, - context: contextDatabase, - hint: "change stream operations are not supported yet", - }, - - // Bulk operations (unsupported) - "collection:initializeOrderedBulkOp": { - status: statusUnsupported, - context: contextCollection, - hint: "bulk operations are not supported yet", - }, - "collection:initializeUnorderedBulkOp": { - status: statusUnsupported, - context: contextCollection, - hint: "bulk operations are not supported yet", - }, - - // Plan cache methods (unsupported) - "collection:getPlanCache": { - status: statusUnsupported, - context: contextCollection, - hint: "plan cache operations are not supported yet", - }, - - // Additional collection methods (unsupported) - "collection:hideIndex": { - status: statusUnsupported, - context: contextCollection, - hint: "index management operations are not supported yet", - }, - "collection:unhideIndex": { - status: statusUnsupported, - context: contextCollection, - hint: "index management operations are not supported yet", - }, - "collection:compactStructuredEncryptionData": { - status: statusUnsupported, - context: contextCollection, - hint: "encryption operations are not supported yet", - }, - - // Additional database methods (unsupported) - "database:currentOp": { - status: statusUnsupported, - context: contextDatabase, - hint: "operation monitoring is not supported yet", - }, - "database:killOp": { - status: statusUnsupported, - context: contextDatabase, - hint: "operation management is not supported yet", - }, - "database:fsyncLock": { - status: statusUnsupported, - context: contextDatabase, - hint: "fsync operations are not supported yet", - }, - "database:fsyncUnlock": { - status: statusUnsupported, - context: contextDatabase, - hint: "fsync operations are not supported yet", - }, - "database:setProfilingLevel": { - status: statusUnsupported, - context: contextDatabase, - hint: "profiling operations are not supported yet", - }, - "database:getProfilingStatus": { - status: statusUnsupported, - context: contextDatabase, - hint: "profiling operations are not supported yet", - }, - "database:setLogLevel": { - status: statusUnsupported, - context: contextDatabase, - hint: "log management is not supported yet", - }, - "database:getLogComponents": { - status: statusUnsupported, - context: contextDatabase, - hint: "log management is not supported yet", - }, - "database:rotateCertificates": { - status: statusUnsupported, - context: contextDatabase, - hint: "certificate operations are not supported yet", - }, - "database:shutdownServer": { - status: statusUnsupported, - context: contextDatabase, - hint: "server management is not supported yet", - }, - - // User/Role management (unsupported) - "database:getUser": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:getUsers": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:updateUser": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:changeUserPassword": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:dropAllUsers": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:grantRolesToUser": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:revokeRolesFromUser": { - status: statusUnsupported, - context: contextDatabase, - hint: "user management operations are not supported yet", - }, - "database:createRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:dropRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:getRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:getRoles": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:updateRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:dropAllRoles": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:grantPrivilegesToRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:revokePrivilegesFromRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:grantRolesToRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, - "database:revokeRolesFromRole": { - status: statusUnsupported, - context: contextDatabase, - hint: "role management operations are not supported yet", - }, + // Atomic Find-and-Modify Commands (3) + "collection:findOneAndUpdate": {status: statusPlanned}, + "collection:findOneAndReplace": {status: statusPlanned}, + "collection:findOneAndDelete": {status: statusPlanned}, // ============================================================ - // CONNECTION METHODS (17) - Mongo(), connect(), connection chain + // MILESTONE 3: Administrative Operations (22 methods) // ============================================================ - "connection:Mongo": { - status: statusUnsupported, - context: contextConnection, - hint: "connection is handled at client creation time", - }, - "connection:connect": { - status: statusUnsupported, - context: contextConnection, - hint: "connection is handled at client creation time", - }, - "connection:getDB": { - status: statusUnsupported, - context: contextConnection, - hint: "database is set at connection time", - }, - "connection:getDBNames": { - status: statusUnsupported, - context: contextConnection, - hint: "use 'show dbs' instead", - }, - "connection:getDBs": { - status: statusUnsupported, - context: contextConnection, - hint: "use 'show dbs' instead", - }, - "connection:getReadPrefMode": { - status: statusUnsupported, - context: contextConnection, - hint: "read preference is set at connection time", - }, - "connection:getReadPrefTagSet": { - status: statusUnsupported, - context: contextConnection, - hint: "read preference is set at connection time", - }, - "connection:getURI": { - status: statusUnsupported, - context: contextConnection, - hint: "connection URI is set at client creation time", - }, - "connection:getWriteConcern": { - status: statusUnsupported, - context: contextConnection, - hint: "write concern is set at connection time", - }, - "connection:setCausalConsistency": { - status: statusUnsupported, - context: contextConnection, - hint: "session management is not supported", - }, - "connection:setReadPref": { - status: statusUnsupported, - context: contextConnection, - hint: "read preference is set at connection time", - }, - "connection:setWriteConcern": { - status: statusUnsupported, - context: contextConnection, - hint: "write concern is set at connection time", - }, - "connection:startSession": { - status: statusUnsupported, - context: contextConnection, - hint: "session management is not supported", - }, - "connection:watch": { - status: statusUnsupported, - context: contextConnection, - hint: "change streams are not supported", - }, - "connection:Session": { - status: statusUnsupported, - context: contextConnection, - hint: "session management is not supported", - }, - "connection:SessionOptions": { - status: statusUnsupported, - context: contextConnection, - hint: "session management is not supported", - }, - // ============================================================ - // REPLICATION METHODS (15) - rs.* methods - // ============================================================ - "replication:add": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:addArb": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:conf": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:freeze": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:help": { - status: statusUnsupported, - context: contextReplication, - hint: "help system is not supported", - }, - "replication:initiate": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:printReplicationInfo": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:printSecondaryReplicationInfo": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:reconfig": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:reconfigForPSASet": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:remove": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:status": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:stepDown": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, - "replication:syncFrom": { - status: statusUnsupported, - context: contextReplication, - hint: "replica set administration is not supported", - }, + // Index Management (4) + "collection:createIndex": {status: statusPlanned}, + "collection:createIndexes": {status: statusPlanned}, + "collection:dropIndex": {status: statusPlanned}, + "collection:dropIndexes": {status: statusPlanned}, - // ============================================================ - // SHARDING METHODS (49) - sh.* methods - // ============================================================ - "sharding:abortMoveCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:abortReshardCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:abortUnshardCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:addShard": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:addShardTag": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:addShardToZone": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:addTagRange": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:balancerCollectionStatus": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:checkMetadataConsistency": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:commitReshardCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:disableAutoMerger": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:disableAutoSplit": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:disableBalancing": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:disableMigrations": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:enableAutoMerger": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:enableAutoSplit": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:enableBalancing": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:enableMigrations": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:enableSharding": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:getBalancerState": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:getShardedDataDistribution": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:help": { - status: statusUnsupported, - context: contextSharding, - hint: "help system is not supported", - }, - "sharding:isBalancerRunning": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:isConfigShardEnabled": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:listShards": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:moveChunk": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:moveCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:moveRange": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:removeRangeFromZone": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:removeShardFromZone": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:removeShardTag": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:removeTagRange": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:reshardCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:setBalancerState": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:shardAndDistributeCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:shardCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:splitAt": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:splitFind": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:startAutoMerger": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:startBalancer": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:status": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:stopAutoMerger": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:stopBalancer": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:unshardCollection": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:updateZoneKeyRange": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:waitForBalancer": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:waitForBalancerOff": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, - "sharding:waitForPingChange": { - status: statusUnsupported, - context: contextSharding, - hint: "sharding administration is not supported", - }, + // Collection Management (4) + "database:createCollection": {status: statusPlanned}, + "collection:drop": {status: statusPlanned}, + "collection:renameCollection": {status: statusPlanned}, + "database:dropDatabase": {status: statusPlanned}, - // ============================================================ - // ENCRYPTION METHODS (18) - KeyVault, ClientEncryption - // ============================================================ - "encryption:ClientEncryption.createEncryptedCollection": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:ClientEncryption.decrypt": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:ClientEncryption.encrypt": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:ClientEncryption.encryptExpression": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:getClientEncryption": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:getKeyVault": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.addKeyAlternateName": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.addKeyAltName": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.createKey": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.createDataKey": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.deleteKey": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.getKey": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.getKeyByAltName": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.getKeys": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.removeKeyAlternateName": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.removeKeyAltName": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - "encryption:KeyVault.rewrapManyDataKey": { - status: statusUnsupported, - context: contextEncryption, - hint: "client-side encryption is not supported", - }, - - // ============================================================ - // BULK OPERATION METHODS (22) - // ============================================================ - "bulk:Bulk": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.execute": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.arrayFilters": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.collation": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.delete": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.deleteOne": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.hint": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.remove": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.removeOne": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.replaceOne": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.update": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.updateOne": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.find.upsert": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.getOperations": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.insert": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.toJSON": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Bulk.toString": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:initializeOrderedBulkOp": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:initializeUnorderedBulkOp": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - "bulk:Mongo.bulkWrite": { - status: statusUnsupported, - context: contextBulk, - hint: "use individual write commands instead", - }, - - // ============================================================ - // PLAN CACHE METHODS (6) - // ============================================================ - "plancache:getPlanCache": { - status: statusUnsupported, - context: contextPlanCache, - hint: "plan cache operations are not supported", - }, - "plancache:PlanCache.clear": { - status: statusUnsupported, - context: contextPlanCache, - hint: "plan cache operations are not supported", - }, - "plancache:PlanCache.clearPlansByQuery": { - status: statusUnsupported, - context: contextPlanCache, - hint: "plan cache operations are not supported", - }, - "plancache:PlanCache.help": { - status: statusUnsupported, - context: contextPlanCache, - hint: "help system is not supported", - }, - "plancache:PlanCache.list": { - status: statusUnsupported, - context: contextPlanCache, - hint: "plan cache operations are not supported", - }, - - // ============================================================ - // STREAM PROCESSING METHODS (10) - sp.* Atlas Stream Processing - // ============================================================ - "stream:createStreamProcessor": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:listConnections": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:listStreamProcessors": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:process": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:processor.drop": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:processor.sample": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:processor.start": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:processor.stats": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - "stream:processor.stop": { - status: statusUnsupported, - context: contextStream, - hint: "Atlas Stream Processing is not supported", - }, - - // ============================================================ - // NATIVE SHELL METHODS (18) - top-level functions - // ============================================================ - "native:_isWindows": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:_rand": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:cat": { - status: statusUnsupported, - context: contextNative, - hint: "file system operations are not supported", - }, - "native:getHostName": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:getMemInfo": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:hostname": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:isInteractive": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:listFiles": { - status: statusUnsupported, - context: contextNative, - hint: "file system operations are not supported", - }, - "native:load": { - status: statusUnsupported, - context: contextNative, - hint: "file system operations are not supported", - }, - "native:ls": { - status: statusUnsupported, - context: contextNative, - hint: "file system operations are not supported", - }, - "native:md5sumFile": { - status: statusUnsupported, - context: contextNative, - hint: "file system operations are not supported", - }, - "native:mkdir": { - status: statusUnsupported, - context: contextNative, - hint: "file system operations are not supported", - }, - "native:quit": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:removeFile": { - status: statusUnsupported, - context: contextNative, - hint: "file system operations are not supported", - }, - "native:sleep": { - status: statusUnsupported, - context: contextNative, - hint: "shell-specific function is not supported", - }, - "native:version": { - status: statusUnsupported, - context: contextNative, - hint: "use db.version() instead", - }, - "native:passwordPrompt": { - status: statusUnsupported, - context: contextNative, - hint: "interactive shell feature is not supported", - }, - - // ============================================================ - // ADDITIONAL DATABASE METHODS from milestone doc - // ============================================================ - "database:aggregate": { - status: statusUnsupported, - context: contextDatabase, - hint: "database-level aggregation is not supported yet", - }, - "database:commandHelp": { - status: statusUnsupported, - context: contextDatabase, - hint: "help system is not supported", - }, - "database:createView": { - status: statusUnsupported, - context: contextDatabase, - hint: "view creation is not supported yet", - }, - "database:getCollection": { - status: statusUnsupported, - context: contextDatabase, - hint: "use db.collectionName syntax directly", - }, - "database:getReplicationInfo": { - status: statusUnsupported, - context: contextDatabase, - hint: "replication information is not supported", - }, - "database:hello": { - status: statusUnsupported, - context: contextDatabase, - hint: "cluster state is not supported", - }, - "database:help": { - status: statusUnsupported, - context: contextDatabase, - hint: "help system is not supported", - }, - "database:logout": { - status: statusDeprecated, - context: contextDatabase, - alternative: "close connection and reconnect", - }, - "database:printCollectionStats": { - status: statusUnsupported, - context: contextDatabase, - hint: "use db.collection.stats() instead", - }, - "database:printReplicationInfo": { - status: statusUnsupported, - context: contextDatabase, - hint: "replication information is not supported", - }, - "database:printSecondaryReplicationInfo": { - status: statusUnsupported, - context: contextDatabase, - hint: "replication information is not supported", - }, - "database:printShardingStatus": { - status: statusUnsupported, - context: contextDatabase, - hint: "sharding information is not supported", - }, - "database:serverCmdLineOpts": { - status: statusUnsupported, - context: contextDatabase, - hint: "server configuration is not supported", - }, - "database:checkMetadataConsistency": { - status: statusUnsupported, - context: contextDatabase, - hint: "cluster administration is not supported", - }, + // Database Information (7) + "database:stats": {status: statusPlanned}, + "collection:stats": {status: statusPlanned}, + "database:serverStatus": {status: statusPlanned}, + "database:serverBuildInfo": {status: statusPlanned}, + "database:version": {status: statusPlanned}, + "database:hostInfo": {status: statusPlanned}, + "database:listCommands": {status: statusPlanned}, - // ============================================================ - // ADDITIONAL COLLECTION METHODS from milestone doc - // ============================================================ - "collection:analyzeShardKey": { - status: statusUnsupported, - context: contextCollection, - hint: "sharding features are not supported", - }, - "collection:configureQueryAnalyzer": { - status: statusUnsupported, - context: contextCollection, - hint: "sharding features are not supported", - }, - "collection:explain": { - status: statusUnsupported, - context: contextCollection, - hint: "explain is not supported yet", - }, - "collection:getShardDistribution": { - status: statusUnsupported, - context: contextCollection, - hint: "sharding features are not supported", - }, - "collection:getShardVersion": { - status: statusUnsupported, - context: contextCollection, - hint: "sharding features are not supported", - }, - "collection:mapReduce": { - status: statusDeprecated, - context: contextCollection, - alternative: "aggregate() with $group and other stages", - }, + // Collection Information (7) + "collection:dataSize": {status: statusPlanned}, + "collection:storageSize": {status: statusPlanned}, + "collection:totalIndexSize": {status: statusPlanned}, + "collection:totalSize": {status: statusPlanned}, + "collection:isCapped": {status: statusPlanned}, + "collection:validate": {status: statusPlanned}, + "collection:latencyStats": {status: statusPlanned}, } -// MethodRegistryStats returns statistics about the method registry. -func MethodRegistryStats() (total, deprecated, unsupported int) { - for _, info := range methodRegistry { - total++ - switch info.status { - case statusDeprecated: - deprecated++ - case statusUnsupported: - unsupported++ - } - } - return total, deprecated, unsupported +// IsPlannedMethod checks if a method is in the registry (planned for implementation). +// Returns true if the method should fallback to mongosh. +// Returns false if the method is unsupported (throw error). +func IsPlannedMethod(context, methodName string) bool { + key := context + ":" + methodName + _, ok := methodRegistry[key] + return ok } -// lookupMethod looks up a method in the registry. -// It first tries the context-specific key, then falls back to a generic lookup. -func lookupMethod(ctx methodContext, methodName string) (methodInfo, bool) { - var contextPrefix string - switch ctx { - case contextCollection: - contextPrefix = "collection:" - case contextCursor: - contextPrefix = "cursor:" - case contextDatabase: - contextPrefix = "database:" - case contextConnection: - contextPrefix = "connection:" - case contextReplication: - contextPrefix = "replication:" - case contextSharding: - contextPrefix = "sharding:" - case contextEncryption: - contextPrefix = "encryption:" - case contextBulk: - contextPrefix = "bulk:" - case contextPlanCache: - contextPrefix = "plancache:" - case contextStream: - contextPrefix = "stream:" - case contextNative: - contextPrefix = "native:" - } - - // Try context-specific lookup first - if info, ok := methodRegistry[contextPrefix+methodName]; ok { - return info, true - } - - // Fall back to generic lookup (for methods that are the same across contexts) - if info, ok := methodRegistry[methodName]; ok { - return info, true - } - - return methodInfo{}, false +// MethodRegistryStats returns statistics about the method registry. +func MethodRegistryStats() int { + return len(methodRegistry) } diff --git a/translator.go b/translator.go index ce853a7..fde59b5 100644 --- a/translator.go +++ b/translator.go @@ -110,7 +110,6 @@ func (v *mongoShellVisitor) visitShellCommand(ctx mongodb.IShellCommandContext) default: v.err = &UnsupportedOperationError{ Operation: ctx.GetText(), - Hint: "unknown shell command", } } } @@ -451,17 +450,27 @@ func (v *mongoShellVisitor) extractFindFilter(ctx mongodb.IFindMethodContext) { return } - arg := fm.Argument() - if arg == nil { + args := fm.Arguments() + if args == nil { return } - argCtx, ok := arg.(*mongodb.ArgumentContext) + argsCtx, ok := args.(*mongodb.ArgumentsContext) if !ok { return } - valueCtx := argCtx.Value() + allArgs := argsCtx.AllArgument() + if len(allArgs) == 0 { + return + } + + firstArg, ok := allArgs[0].(*mongodb.ArgumentContext) + if !ok { + return + } + + valueCtx := firstArg.Value() if valueCtx == nil { return } @@ -486,17 +495,27 @@ func (v *mongoShellVisitor) extractFindOneFilter(ctx mongodb.IFindOneMethodConte return } - arg := fm.Argument() - if arg == nil { + args := fm.Arguments() + if args == nil { return } - argCtx, ok := arg.(*mongodb.ArgumentContext) + argsCtx, ok := args.(*mongodb.ArgumentsContext) if !ok { return } - valueCtx := argCtx.Value() + allArgs := argsCtx.AllArgument() + if len(allArgs) == 0 { + return + } + + firstArg, ok := allArgs[0].(*mongodb.ArgumentContext) + if !ok { + return + } + + valueCtx := firstArg.Value() if valueCtx == nil { return } @@ -601,218 +620,148 @@ func (v *mongoShellVisitor) visitMethodCall(ctx mongodb.IMethodCallContext) { return } - // Determine method context for error messages - getMethodContext := func() methodContext { + // Determine method context for registry lookup + getMethodContext := func() string { if v.operation.opType == opFind || v.operation.opType == opFindOne { - return contextCursor + return "cursor" } - return contextCollection + return "collection" } + switch { // Supported read operations - if mc.FindMethod() != nil { + case mc.FindMethod() != nil: v.operation.opType = opFind v.extractFindFilter(mc.FindMethod()) - } else if mc.FindOneMethod() != nil { + case mc.FindOneMethod() != nil: v.operation.opType = opFindOne v.extractFindOneFilter(mc.FindOneMethod()) - } else if mc.CountDocumentsMethod() != nil { + case mc.CountDocumentsMethod() != nil: v.operation.opType = opCountDocuments v.extractCountDocumentsArgsFromMethod(mc.CountDocumentsMethod()) - } else if mc.EstimatedDocumentCountMethod() != nil { + case mc.EstimatedDocumentCountMethod() != nil: v.operation.opType = opEstimatedDocumentCount - } else if mc.DistinctMethod() != nil { + case mc.DistinctMethod() != nil: v.operation.opType = opDistinct v.extractDistinctArgsFromMethod(mc.DistinctMethod()) - } else if mc.AggregateMethod() != nil { + case mc.AggregateMethod() != nil: v.operation.opType = opAggregate v.extractAggregationPipelineFromMethod(mc.AggregateMethod()) - } else if mc.GetIndexesMethod() != nil { + case mc.GetIndexesMethod() != nil: v.operation.opType = opGetIndexes - } else if mc.SortMethod() != nil { - // Supported cursor modifiers + + // Supported cursor modifiers + case mc.SortMethod() != nil: v.extractSort(mc.SortMethod()) - } else if mc.LimitMethod() != nil { + case mc.LimitMethod() != nil: v.extractLimit(mc.LimitMethod()) - } else if mc.SkipMethod() != nil { + case mc.SkipMethod() != nil: v.extractSkip(mc.SkipMethod()) - } else if mc.ProjectionMethod() != nil { + case mc.ProjectionMethod() != nil: v.extractProjection(mc.ProjectionMethod()) - } else if mc.CountMethod() != nil { - // Deprecated cursor method - v.handleUnsupportedMethod(contextCursor, "count") - } else if mc.InsertOneMethod() != nil { - // Unsupported write operations - v.handleUnsupportedMethod(contextCollection, "insertOne") - } else if mc.InsertManyMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "insertMany") - } else if mc.UpdateOneMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "updateOne") - } else if mc.UpdateManyMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "updateMany") - } else if mc.DeleteOneMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "deleteOne") - } else if mc.DeleteManyMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "deleteMany") - } else if mc.ReplaceOneMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "replaceOne") - } else if mc.FindOneAndUpdateMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "findOneAndUpdate") - } else if mc.FindOneAndReplaceMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "findOneAndReplace") - } else if mc.FindOneAndDeleteMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "findOneAndDelete") - } else if mc.CreateIndexMethod() != nil { - // Unsupported index operations - v.handleUnsupportedMethod(contextCollection, "createIndex") - } else if mc.CreateIndexesMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "createIndexes") - } else if mc.DropIndexMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "dropIndex") - } else if mc.DropIndexesMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "dropIndexes") - } else if mc.DropMethod() != nil { - // Unsupported collection management - v.handleUnsupportedMethod(contextCollection, "drop") - } else if mc.RenameCollectionMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "renameCollection") - } else if mc.StatsMethod() != nil { - // Unsupported stats operations - v.handleUnsupportedMethod(contextCollection, "stats") - } else if mc.StorageSizeMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "storageSize") - } else if mc.TotalIndexSizeMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "totalIndexSize") - } else if mc.TotalSizeMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "totalSize") - } else if mc.DataSizeMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "dataSize") - } else if mc.IsCappedMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "isCapped") - } else if mc.ValidateMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "validate") - } else if mc.LatencyStatsMethod() != nil { - v.handleUnsupportedMethod(contextCollection, "latencyStats") - } else if mc.BatchSizeMethod() != nil { - // Unsupported cursor methods - v.handleUnsupportedMethod(contextCursor, "batchSize") - } else if mc.CloseMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "close") - } else if mc.CollationMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "collation") - } else if mc.CommentMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "comment") - } else if mc.ExplainMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "explain") - } else if mc.ForEachMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "forEach") - } else if mc.HasNextMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "hasNext") - } else if mc.HintMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "hint") - } else if mc.IsClosedMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "isClosed") - } else if mc.IsExhaustedMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "isExhausted") - } else if mc.ItcountMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "itcount") - } else if mc.MapMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "map") - } else if mc.MaxMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "max") - } else if mc.MaxAwaitTimeMSMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "maxAwaitTimeMS") - } else if mc.MaxTimeMSMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "maxTimeMS") - } else if mc.MinMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "min") - } else if mc.NextMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "next") - } else if mc.NoCursorTimeoutMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "noCursorTimeout") - } else if mc.ObjsLeftInBatchMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "objsLeftInBatch") - } else if mc.PrettyMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "pretty") - } else if mc.ReadConcernMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "readConcern") - } else if mc.ReadPrefMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "readPref") - } else if mc.ReturnKeyMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "returnKey") - } else if mc.ShowRecordIdMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "showRecordId") - } else if mc.SizeMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "size") - } else if mc.TailableMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "tailable") - } else if mc.ToArrayMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "toArray") - } else if mc.TryNextMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "tryNext") - } else if mc.AllowDiskUseMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "allowDiskUse") - } else if mc.AddOptionMethod() != nil { - v.handleUnsupportedMethod(contextCursor, "addOption") - } else if gm := mc.GenericMethod(); gm != nil { - // Fallback for any methods not explicitly handled above - gmCtx, ok := gm.(*mongodb.GenericMethodContext) + + // Planned M2 write operations - return PlannedOperationError for fallback + case mc.InsertOneMethod() != nil: + v.handleUnsupportedMethod("collection", "insertOne") + case mc.InsertManyMethod() != nil: + v.handleUnsupportedMethod("collection", "insertMany") + case mc.UpdateOneMethod() != nil: + v.handleUnsupportedMethod("collection", "updateOne") + case mc.UpdateManyMethod() != nil: + v.handleUnsupportedMethod("collection", "updateMany") + case mc.DeleteOneMethod() != nil: + v.handleUnsupportedMethod("collection", "deleteOne") + case mc.DeleteManyMethod() != nil: + v.handleUnsupportedMethod("collection", "deleteMany") + case mc.ReplaceOneMethod() != nil: + v.handleUnsupportedMethod("collection", "replaceOne") + case mc.FindOneAndUpdateMethod() != nil: + v.handleUnsupportedMethod("collection", "findOneAndUpdate") + case mc.FindOneAndReplaceMethod() != nil: + v.handleUnsupportedMethod("collection", "findOneAndReplace") + case mc.FindOneAndDeleteMethod() != nil: + v.handleUnsupportedMethod("collection", "findOneAndDelete") + + // Planned M3 index operations - return PlannedOperationError for fallback + case mc.CreateIndexMethod() != nil: + v.handleUnsupportedMethod("collection", "createIndex") + case mc.CreateIndexesMethod() != nil: + v.handleUnsupportedMethod("collection", "createIndexes") + case mc.DropIndexMethod() != nil: + v.handleUnsupportedMethod("collection", "dropIndex") + case mc.DropIndexesMethod() != nil: + v.handleUnsupportedMethod("collection", "dropIndexes") + + // Planned M3 collection management - return PlannedOperationError for fallback + case mc.DropMethod() != nil: + v.handleUnsupportedMethod("collection", "drop") + case mc.RenameCollectionMethod() != nil: + v.handleUnsupportedMethod("collection", "renameCollection") + + // Planned M3 stats operations - return PlannedOperationError for fallback + case mc.StatsMethod() != nil: + v.handleUnsupportedMethod("collection", "stats") + case mc.StorageSizeMethod() != nil: + v.handleUnsupportedMethod("collection", "storageSize") + case mc.TotalIndexSizeMethod() != nil: + v.handleUnsupportedMethod("collection", "totalIndexSize") + case mc.TotalSizeMethod() != nil: + v.handleUnsupportedMethod("collection", "totalSize") + case mc.DataSizeMethod() != nil: + v.handleUnsupportedMethod("collection", "dataSize") + case mc.IsCappedMethod() != nil: + v.handleUnsupportedMethod("collection", "isCapped") + case mc.ValidateMethod() != nil: + v.handleUnsupportedMethod("collection", "validate") + case mc.LatencyStatsMethod() != nil: + v.handleUnsupportedMethod("collection", "latencyStats") + + // Generic method fallback - all methods going through genericMethod are unsupported + case mc.GenericMethod() != nil: + gmCtx, ok := mc.GenericMethod().(*mongodb.GenericMethodContext) if !ok { return } methodName := gmCtx.Identifier().GetText() + v.handleUnsupportedMethod(getMethodContext(), methodName) - // Handle supported methods that may come through genericMethod - // (e.g., aggregate() with no arguments goes to genericMethod, not aggregateMethod) - switch methodName { - case "aggregate": - v.operation.opType = opAggregate - v.extractArgumentsForAggregate(gmCtx.Arguments()) - case "countDocuments": - v.operation.opType = opCountDocuments - v.extractArgumentsForCountDocuments(gmCtx.Arguments()) - case "estimatedDocumentCount": - v.operation.opType = opEstimatedDocumentCount - case "distinct": - v.operation.opType = opDistinct - v.extractArgumentsForDistinct(gmCtx.Arguments()) - case "getIndexes": - v.operation.opType = opGetIndexes - default: + // Default: all other methods not explicitly handled + // These go to handleUnsupportedMethod which returns UnsupportedOperationError + // since they're not in the planned registry + default: + // Extract method name from the parse tree for error message + methodName := v.extractMethodName(mc) + if methodName != "" { v.handleUnsupportedMethod(getMethodContext(), methodName) } } } +// extractMethodName extracts the method name from a MethodCallContext for error messages. +func (v *mongoShellVisitor) extractMethodName(mc *mongodb.MethodCallContext) string { + // Try to get method name from various method contexts + // The parser creates specific method contexts for known methods + // For unknown methods, they go through GenericMethod which is handled separately + text := mc.GetText() + // Extract method name before the opening parenthesis + if idx := strings.Index(text, "("); idx > 0 { + return text[:idx] + } + return text +} + // handleUnsupportedMethod checks the method registry and returns appropriate errors. -func (v *mongoShellVisitor) handleUnsupportedMethod(ctx methodContext, methodName string) { - info, found := lookupMethod(ctx, methodName) - if !found { - // Method not in registry - unknown method - v.err = &UnsupportedOperationError{ +// If method is in registry (planned for M2/M3) -> PlannedOperationError (fallback to mongosh) +// If method is NOT in registry -> UnsupportedOperationError (no fallback) +func (v *mongoShellVisitor) handleUnsupportedMethod(context, methodName string) { + if IsPlannedMethod(context, methodName) { + v.err = &PlannedOperationError{ Operation: methodName + "()", - Hint: "unknown method", } return } - - switch info.status { - case statusDeprecated: - v.err = &DeprecatedOperationError{ - Operation: methodName + "()", - Alternative: info.alternative, - } - case statusUnsupported: - v.err = &UnsupportedOperationError{ - Operation: methodName + "()", - Hint: info.hint, - } - case statusSupported: - // This shouldn't happen - supported methods should be handled explicitly - v.err = &UnsupportedOperationError{ - Operation: methodName + "()", - Hint: "method is supported but not handled", - } + v.err = &UnsupportedOperationError{ + Operation: methodName + "()", } }