diff --git a/collection_test.go b/collection_test.go index 0aaf4ba..7d911a1 100644 --- a/collection_test.go +++ b/collection_test.go @@ -2262,3 +2262,38 @@ func TestCursorMinMethod(t *testing.T) { require.Equal(t, 2, len(result.Value)) }) } + +func TestPrettyNoOp(t *testing.T) { + testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) { + dbName := fmt.Sprintf("testdb_pretty_%s", db.Name) + defer testutil.CleanupDatabase(t, db.Client, dbName) + + ctx := context.Background() + collection := db.Client.Database(dbName).Collection("users") + // Insert in reverse alphabetical order so sort assertions are meaningful. + _, err := collection.InsertMany(ctx, []any{ + bson.M{"name": "bob", "age": 25}, + bson.M{"name": "alice", "age": 30}, + }) + require.NoError(t, err) + + gc := gomongo.NewClient(db.Client) + + // pretty() should be a no-op cursor method + result, err := gc.Execute(ctx, dbName, `db.users.find().pretty()`) + require.NoError(t, err) + require.Equal(t, 2, len(result.Value)) + + // pretty() chained after sort — inserted bob first, sort should put alice first + result, err = gc.Execute(ctx, dbName, `db.users.find().sort({name: 1}).pretty()`) + require.NoError(t, err) + require.Equal(t, 2, len(result.Value)) + rows := valuesToStrings(result.Value) + require.Contains(t, rows[0], `"alice"`) + + // aggregate().pretty() + result, err = gc.Execute(ctx, dbName, `db.users.aggregate([{$match: {name: "alice"}}]).pretty()`) + require.NoError(t, err) + require.Equal(t, 1, len(result.Value)) + }) +} diff --git a/go.mod b/go.mod index a9a84e6..3bcfc1d 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-20260130090605-effef73942d9 + github.com/bytebase/parser v0.0.0-20260324035613-3b4d6e704551 github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.40.0 diff --git a/go.sum b/go.sum index 75686f2..c1d7adb 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-20260130090605-effef73942d9 h1:q5MnVPWlV/p3MPe60SysVoUaEnyeS6+OOOk0F3DLLK8= -github.com/bytebase/parser v0.0.0-20260130090605-effef73942d9/go.mod h1:jeak/EfutSOAuWKvrFIT2IZunhWprM7oTFBRgZ9RCxo= +github.com/bytebase/parser v0.0.0-20260324035613-3b4d6e704551 h1:jmOIMyIEXoMWZ+TK91STbBMPRom7S/tWxosxYZDg9jk= +github.com/bytebase/parser v0.0.0-20260324035613-3b4d6e704551/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/internal/translator/bson_helpers.go b/internal/translator/bson_helpers.go index 0a39aa4..73f6a26 100644 --- a/internal/translator/bson_helpers.go +++ b/internal/translator/bson_helpers.go @@ -178,18 +178,22 @@ func convertLongHelper(ctx mongodb.ILongHelperContext) (int64, error) { return strconv.ParseInt(numStr, 10, 64) } -// convertInt32Helper converts Int32(123) or NumberInt(123) to int32. +// convertInt32Helper converts Int32(123), Int32("123"), NumberInt(123), or NumberInt("123") to int32. func convertInt32Helper(ctx mongodb.IInt32HelperContext) (int32, error) { helper, ok := ctx.(*mongodb.Int32HelperContext) if !ok { return 0, fmt.Errorf("invalid Int32 helper context") } - if helper.NUMBER() == nil { + var numStr string + if helper.NUMBER() != nil { + numStr = helper.NUMBER().GetText() + } else if helper.StringLiteral() != nil { + numStr = unquoteString(helper.StringLiteral().GetText()) + } else { return 0, nil } - numStr := helper.NUMBER().GetText() i, err := strconv.ParseInt(numStr, 10, 32) if err != nil { return 0, err diff --git a/internal/translator/bson_helpers_test.go b/internal/translator/bson_helpers_test.go index bd6fb05..c90dcc6 100644 --- a/internal/translator/bson_helpers_test.go +++ b/internal/translator/bson_helpers_test.go @@ -204,3 +204,49 @@ func TestDecimal128Helper(t *testing.T) { require.NotNil(t, price) }) } + +func TestInt32StringArg(t *testing.T) { + testutil.RunOnAllDBs(t, func(t *testing.T, db testutil.TestDB) { + dbName := "testdb_int32str_" + db.Name + defer testutil.CleanupDatabase(t, db.Client, dbName) + + gc := gomongo.NewClient(db.Client) + ctx := context.Background() + + // Int32("123") should parse the string as int32 + _, err := gc.Execute(ctx, dbName, `db.test.insertOne({val: Int32("123")})`) + require.NoError(t, err) + + result, err := gc.Execute(ctx, dbName, `db.test.findOne({})`) + require.NoError(t, err) + require.Equal(t, 1, len(result.Value)) + doc, ok := result.Value[0].(bson.D) + require.True(t, ok) + val := getDocField(doc, "val") + require.Equal(t, int32(123), val) + + // NumberInt("456") should also work + _, err = gc.Execute(ctx, dbName, `db.test.insertOne({val2: NumberInt("456")})`) + require.NoError(t, err) + + result, err = gc.Execute(ctx, dbName, `db.test.findOne({val2: {$exists: true}})`) + require.NoError(t, err) + require.Equal(t, 1, len(result.Value)) + doc, ok = result.Value[0].(bson.D) + require.True(t, ok) + val2 := getDocField(doc, "val2") + require.Equal(t, int32(456), val2) + + // NumberLong("1774250313") — from real user report + _, err = gc.Execute(ctx, dbName, `db.test.insertOne({val3: NumberLong("1774250313")})`) + require.NoError(t, err) + + result, err = gc.Execute(ctx, dbName, `db.test.findOne({val3: {$exists: true}})`) + require.NoError(t, err) + require.Equal(t, 1, len(result.Value)) + doc, ok = result.Value[0].(bson.D) + require.True(t, ok) + val3 := getDocField(doc, "val3") + require.Equal(t, int64(1774250313), val3) + }) +} diff --git a/internal/translator/collection.go b/internal/translator/collection.go index 0857ee1..571161b 100644 --- a/internal/translator/collection.go +++ b/internal/translator/collection.go @@ -2225,3 +2225,4 @@ func (v *visitor) extractCreateIndexesArgs(ctx mongodb.ICreateIndexesMethodConte return } } + diff --git a/internal/translator/visitor.go b/internal/translator/visitor.go index 06bcca6..1c612c6 100644 --- a/internal/translator/visitor.go +++ b/internal/translator/visitor.go @@ -281,6 +281,8 @@ func (v *visitor) visitCursorMethodCall(ctx mongodb.ICursorMethodCallContext) { v.extractMax(mc.MaxMethod()) case mc.MinMethod() != nil: v.extractMin(mc.MinMethod()) + case mc.PrettyMethod() != nil: + // pretty() is a no-op — output is already formatted. default: methodName := extractMethodNameFromText(mc.GetText()) if methodName != "" {