-
Notifications
You must be signed in to change notification settings - Fork 107
feat: custom converter interface for database/sql query parameters #1967
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
base: master
Are you sure you want to change the base?
Changes from all commits
26c839f
ce92874
41d2f4c
197b22b
74ddafe
e4c4d68
19a735d
3532a24
35365db
55c836b
ed883ff
2a25882
ac26a81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| package bind | ||
|
|
||
| import ( | ||
| "github.com/ydb-platform/ydb-go-sdk/v3/internal/bind" | ||
| "github.com/ydb-platform/ydb-go-sdk/v3/internal/value" | ||
| ) | ||
|
|
||
| // Converter defines the interface for custom conversion of database/sql query parameters | ||
| // to YDB values. Implementations can handle specific types that require special conversion | ||
| // logic beyond the standard type conversions. | ||
| // | ||
| // Example: | ||
| // | ||
| // type MyCustomType struct { | ||
| // Field string | ||
| // } | ||
| // | ||
| // func (c *MyCustomConverter) Convert(v any) (value.Value, bool) { | ||
| // if custom, ok := v.(MyCustomType); ok { | ||
| // return value.TextValue(custom.Field), true | ||
| // } | ||
| // return nil, false | ||
| // } | ||
| type Converter = bind.Converter | ||
|
|
||
| // NamedValueConverter extends Converter to handle driver.NamedValue types | ||
| // | ||
| // This is useful when you need access to both the name and value of a parameter | ||
| // for conversion logic. | ||
| // | ||
| // Example: | ||
| // | ||
| // func (c *MyNamedConverter) ConvertNamedValue(nv driver.NamedValue) (value.Value, bool) { | ||
| // if nv.Name == "special_param" { | ||
| // // Custom handling for named parameter | ||
| // return value.TextValue(fmt.Sprintf("special_%v", nv.Value)), true | ||
| // } | ||
| // return c.Convert(nv.Value) | ||
| // } | ||
| type NamedValueConverter = bind.NamedValueConverter | ||
|
|
||
| // RegisterConverter registers a custom converter with the default registry | ||
| // | ||
| // Custom converters are tried before the standard conversion logic, allowing | ||
| // you to override or extend the default behavior for specific types. | ||
| // | ||
| // Example: | ||
| // | ||
| // bind.RegisterConverter(&MyCustomConverter{}) | ||
| func RegisterConverter(converter Converter) { | ||
| bind.RegisterConverter(converter) | ||
| } | ||
|
|
||
| // RegisterNamedValueConverter registers a named value converter with the default registry | ||
| // | ||
| // Named value converters are tried before standard converters when handling | ||
| // driver.NamedValue instances. | ||
| // | ||
| // Example: | ||
| // | ||
| // bind.RegisterNamedValueConverter(&MyNamedConverter{}) | ||
| func RegisterNamedValueConverter(converter NamedValueConverter) { | ||
| bind.RegisterNamedValueConverter(converter) | ||
| } | ||
|
Comment on lines
+54
to
+64
|
||
|
|
||
| // CustomTypeConverter is a generic converter that can be configured with custom conversion functions | ||
| // | ||
| // This provides a convenient way to create converters without defining a new type. | ||
| // | ||
| // Example: | ||
| // | ||
| // converter := bind.NewCustomTypeConverter( | ||
| // func(v any) bool { _, ok := v.(MyType); return ok }, | ||
| // func(v any) (value.Value, error) { return value.TextValue(v.(MyType).String()), nil }, | ||
| // ) | ||
| // bind.RegisterConverter(converter) | ||
| type CustomTypeConverter = bind.CustomTypeConverter | ||
|
|
||
| // NewCustomTypeConverter creates a new custom type converter | ||
| // | ||
| // typeCheck: function that returns true if the converter can handle the given value | ||
| // convertFunc: function that converts the value to a YDB value | ||
| func NewCustomTypeConverter( | ||
| typeCheck func(any) bool, | ||
| convertFunc func(any) (value.Value, error), | ||
| ) *CustomTypeConverter { | ||
| return bind.NewCustomTypeConverter(typeCheck, convertFunc) | ||
| } | ||
|
|
||
| // JSONConverter handles conversion of JSON documents to YDB JSON values | ||
| // | ||
| // This converter automatically handles any type that implements json.Marshaler | ||
| type JSONConverter = bind.JSONConverter | ||
|
|
||
| // UUIDConverter handles conversion of UUID types to YDB UUID values | ||
| // | ||
| // This converter handles google/uuid.UUID and pointer types | ||
| type UUIDConverter = bind.UUIDConverter | ||
|
|
||
| // ConverterRegistry manages a collection of custom converters | ||
| // | ||
| // You can create your own registry if you want to use a separate set of converters | ||
| // from the global default registry. | ||
| type ConverterRegistry = bind.ConverterRegistry | ||
|
|
||
| // NewConverterRegistry creates a new converter registry | ||
| func NewConverterRegistry() *ConverterRegistry { | ||
| return bind.NewConverterRegistry() | ||
| } | ||
|
|
||
| // NamedValueConverterRegistry manages a collection of named value converters | ||
| type NamedValueConverterRegistry = bind.NamedValueConverterRegistry | ||
|
|
||
| // NewNamedValueConverterRegistry creates a new named value converter registry | ||
| func NewNamedValueConverterRegistry() *NamedValueConverterRegistry { | ||
| return bind.NewNamedValueConverterRegistry() | ||
| } | ||
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 documentation should mention that
RegisterConverterregisters converters globally and that registrations persist for the lifetime of the application. This is important for users to understand potential side effects, especially in testing scenarios where converters may need to be cleaned up.