diff --git a/internal/options/options.go b/internal/options/options.go new file mode 100644 index 0000000000..8d5f47f422 --- /dev/null +++ b/internal/options/options.go @@ -0,0 +1,45 @@ +// Copyright (C) MongoDB, Inc. 2025-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package options + +// Options stores internal options. +type Options struct { + values map[string]any +} + +// WithValue sets an option value with the associated key. +func WithValue(opts Options, key string, option any) Options { + if opts.values == nil { + opts.values = make(map[string]any) + } + opts.values[key] = option + return opts +} + +// Value returns the value associated with the options for key. +func Value(opts Options, key string) any { + if opts.values == nil { + return nil + } + if val, ok := opts.values[key]; ok { + return val + } + return nil +} + +// Equal compares two Options instances for equality. +func Equal(opts1, opts2 Options) bool { + if len(opts1.values) != len(opts2.values) { + return false + } + for key, val1 := range opts1.values { + if val2, ok := opts2.values[key]; !ok || val1 != val2 { + return false + } + } + return true +} diff --git a/mongo/options/clientoptions.go b/mongo/options/clientoptions.go index 925325c6c5..2aa94f8960 100644 --- a/mongo/options/clientoptions.go +++ b/mongo/options/clientoptions.go @@ -26,6 +26,7 @@ import ( "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/event" "go.mongodb.org/mongo-driver/v2/internal/httputil" + "go.mongodb.org/mongo-driver/v2/internal/options" "go.mongodb.org/mongo-driver/v2/mongo/readconcern" "go.mongodb.org/mongo-driver/v2/mongo/readpref" "go.mongodb.org/mongo-driver/v2/mongo/writeconcern" @@ -295,6 +296,12 @@ type ClientOptions struct { // release. Deployment driver.Deployment + // Custom specifies internal options for the new Client. + // + // Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any + // release. + Custom options.Options + connString *connstring.ConnString err error } diff --git a/mongo/options/clientoptions_test.go b/mongo/options/clientoptions_test.go index 907584d5f0..a8a00122e0 100644 --- a/mongo/options/clientoptions_test.go +++ b/mongo/options/clientoptions_test.go @@ -27,6 +27,7 @@ import ( "go.mongodb.org/mongo-driver/v2/event" "go.mongodb.org/mongo-driver/v2/internal/assert" "go.mongodb.org/mongo-driver/v2/internal/httputil" + "go.mongodb.org/mongo-driver/v2/internal/options" "go.mongodb.org/mongo-driver/v2/internal/ptrutil" "go.mongodb.org/mongo-driver/v2/mongo/readconcern" "go.mongodb.org/mongo-driver/v2/mongo/readpref" @@ -156,6 +157,7 @@ func TestClientOptions(t *testing.T) { cmp.Comparer(func(r1, r2 *bson.Registry) bool { return r1 == r2 }), cmp.Comparer(func(cfg1, cfg2 *tls.Config) bool { return cfg1 == cfg2 }), cmp.Comparer(func(fp1, fp2 *event.PoolMonitor) bool { return fp1 == fp2 }), + cmp.Comparer(options.Equal), cmp.AllowUnexported(ClientOptions{}), cmpopts.IgnoreFields(http.Client{}, "Transport"), ); diff != "" { @@ -1253,6 +1255,7 @@ func TestApplyURI(t *testing.T) { cmp.Comparer(func(r1, r2 *bson.Registry) bool { return r1 == r2 }), cmp.Comparer(compareTLSConfig), cmp.Comparer(compareErrors), + cmp.Comparer(options.Equal), cmpopts.SortSlices(stringLess), cmpopts.IgnoreFields(connstring.ConnString{}, "SSLClientCertificateKeyPassword"), cmpopts.IgnoreFields(http.Client{}, "Transport"), diff --git a/x/mongo/driver/options/options.go b/x/mongo/driver/options/options.go new file mode 100644 index 0000000000..bc18228f1d --- /dev/null +++ b/x/mongo/driver/options/options.go @@ -0,0 +1,38 @@ +// Copyright (C) MongoDB, Inc. 2025-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package options + +import ( + "fmt" + + "go.mongodb.org/mongo-driver/v2/mongo/options" + "go.mongodb.org/mongo-driver/v2/x/mongo/driver" +) + +// SetInternalClientOptions sets internal options for ClientOptions. +// +// Deprecated: This function is for internal use only. It may be changed or removed in any release. +func SetInternalClientOptions(opts *options.ClientOptions, key string, option any) error { + const typeErr = "unexpected type for %s" + switch key { + case "crypt": + c, ok := option.(driver.Crypt) + if !ok { + return fmt.Errorf(typeErr, key) + } + opts.Crypt = c + case "deployment": + d, ok := option.(driver.Deployment) + if !ok { + return fmt.Errorf(typeErr, key) + } + opts.Deployment = d + default: + return fmt.Errorf("unsupported option: %s", key) + } + return nil +} diff --git a/x/mongo/driver/options/options_test.go b/x/mongo/driver/options/options_test.go new file mode 100644 index 0000000000..a3cdc90600 --- /dev/null +++ b/x/mongo/driver/options/options_test.go @@ -0,0 +1,64 @@ +// Copyright (C) MongoDB, Inc. 2025-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +package options + +import ( + "testing" + + "go.mongodb.org/mongo-driver/v2/internal/require" + "go.mongodb.org/mongo-driver/v2/mongo/options" + "go.mongodb.org/mongo-driver/v2/x/mongo/driver" + "go.mongodb.org/mongo-driver/v2/x/mongo/driver/drivertest" +) + +func TestSetInternalClientOptions(t *testing.T) { + t.Parallel() + + t.Run("set crypt", func(t *testing.T) { + t.Parallel() + + c := driver.NewCrypt(&driver.CryptOptions{}) + opts := options.Client() + err := SetInternalClientOptions(opts, "crypt", c) + require.NoError(t, err, "error setting crypt: %v", err) + require.Equal(t, c, opts.Crypt, "expected %v, got %v", c, opts.Crypt) + }) + + t.Run("set crypt - wrong type", func(t *testing.T) { + t.Parallel() + + opts := options.Client() + err := SetInternalClientOptions(opts, "crypt", &drivertest.MockDeployment{}) + require.EqualError(t, err, "unexpected type for crypt") + }) + + t.Run("set deployment", func(t *testing.T) { + t.Parallel() + + d := &drivertest.MockDeployment{} + opts := options.Client() + err := SetInternalClientOptions(opts, "deployment", d) + require.NoError(t, err, "error setting deployment: %v", err) + require.Equal(t, d, opts.Deployment, "expected %v, got %v", d, opts.Deployment) + }) + + t.Run("set deployment - wrong type", func(t *testing.T) { + t.Parallel() + + opts := options.Client() + err := SetInternalClientOptions(opts, "deployment", driver.NewCrypt(&driver.CryptOptions{})) + require.EqualError(t, err, "unexpected type for deployment") + }) + + t.Run("set unsupported option", func(t *testing.T) { + t.Parallel() + + opts := options.Client() + err := SetInternalClientOptions(opts, "unsupported", "unsupported") + require.EqualError(t, err, "unsupported option: unsupported") + }) +}