Skip to content
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

dynamodb/attributevalue: Support Text(Un)marshaler interfaces to avoid using special marshalers in simple cases #645

Closed
finnbear opened this issue Jul 15, 2020 · 1 comment · Fixed by #1590
Labels
feature-request A feature should be added or improved.

Comments

@finnbear
Copy link

finnbear commented Jul 15, 2020

Is your feature request related to a problem? Please describe.
In my project, I have several enumerators like

type ToolType int
const (
    HammerTool ToolType = iota
    TrowelTool
    FrameTool
    PistolTool
    CannonTool
)

type Entity struct {
    Object
    Tool ToolType `json:"tool"` `dynamodbav:"tool,string"` // Marshaled in dynamo as {S: "2"} not {S: "frame"}, for example
    ...
}

I have defined MarshalText and UnmarshalText for each of them, so that they may be serialized as strings in JSON.

func (toolType ToolType) MarshalText() ([]byte, error) {
    switch toolType {
    case HammerTool:
        return []byte("hammer"), nil
    case TrowelTool:
        return []byte("trowel"), nil
    case FrameTool:
        return []byte("frame"), nil
    case PistolTool:
        return []byte("pistol"), nil
    case CannonTool:
        return []byte("cannon"), nil
    default:
        return nil, errors.New("Unknown tool " + fmt.Sprint(toolType))
    }
}

func (toolType *ToolType) UnmarshalText(text []byte) error {
    switch string(text) {
    case "hammer":
        *toolType = HammerTool
    case "trowel":
        *toolType = TrowelTool
    case "frame":
        *toolType = FrameTool
    case "pistol":
        *toolType = PistolTool
    case "cannon":
        *toolType = CannonTool
    default:
        return errors.New("Unknown tool " + string(text))
    }
    return nil
}

I want to do the same in DynamoDB, but the only option is to create special DynamoDB marshalers and unmarshalers. The issue is that those special marshalers must be defined in the same package (due to Go's rules), and that is impossible in my project as the package that defines the enumerator type is shared with a client-side WebAssembly application that cannot afford to include an import of AWS SDK.

Describe the solution you'd like
If the struct tag string is used, and the type supports the Text(Un)marshaler interface, marshal/unmarshal using that interface.

Describe alternatives you've considered
I've switched all my code to https://github.com/guregu/dynamo which supports this feature (even without a special struct tag). This one issue is the only reason I switched.

You could also add a new struct tag text in reference to TextMarshaler

Additional context
Full details in Go forum question: https://forum.golangbridge.org/t/implementing-custom-marshalers-unmarshalers-on-imported-types/19680

Issue initially filed under V1: aws/aws-sdk-go#3419

@finnbear finnbear added the feature-request A feature should be added or improved. label Jul 15, 2020
@finnbear finnbear changed the title Support Text(Un)marshaler interfaces to avoid using special marshalers in simple cases [dynamodb] Support Text(Un)marshaler interfaces to avoid using special marshalers in simple cases Jul 15, 2020
@jasdel jasdel changed the title [dynamodb] Support Text(Un)marshaler interfaces to avoid using special marshalers in simple cases dynamodb/attributevalue: Support Text(Un)marshaler interfaces to avoid using special marshalers in simple cases Nov 12, 2020
jasdel added a commit to jasdel/aws-sdk-go-v2 that referenced this issue Feb 17, 2022
Updates the `attributevalue` and `expression` package's handling of
AttributeValue marshaling fixing several bugs in the packages.

* Fixes aws#1569 `Inconsistent struct field name marshaled`. Fields will now
  be consistent with the EncoderOptions or DecoderOptions the Go struct
  was used with. Previously the Go struct fields would be cached with
  the first options used for the type. Causes subsequent usages to have
  the wrong field names if the encoding options used different TagKeys.

* Fixes aws#645, aws#411 `Support more than string types for map keys`. Updates
  (un)marshaler to support number, bool, and types that implement
  encoding.Text(Un)Marshaler interfaces.

* Fixes Support for expression Names with literal dots in name. Adds new
  function NameNoDotSplit to expression package. This function allows
  you to provide a literal expression Name containing dots. Also adds a
  new method to NameBuilder, AppendName, for joining multiple name path
  components together. Helpful for joining names with literal dots with
  subsequent object path fields.

* Fixes bug with AttributeValue marshaler struct struct tag usage that
  caused TagKey to be ignored if the member had a struct tag with
  `dynamodbav` struct tag. Now both tags will be read as documented,
  with the TagKey struct tag options taking precedence.
jasdel added a commit that referenced this issue Feb 22, 2022
Updates the `attributevalue` and `expression` package's handling of
AttributeValue marshaling fixing several bugs in the packages.

* Fixes #1569 `Inconsistent struct field name marshaled`. Fields will now
  be consistent with the EncoderOptions or DecoderOptions the Go struct
  was used with. Previously the Go struct fields would be cached with
  the first options used for the type. Causes subsequent usages to have
  the wrong field names if the encoding options used different TagKeys.

* Fixes #645, #411 `Support more than string types for map keys`. Updates
  (un)marshaler to support number, bool, and types that implement
  encoding.Text(Un)Marshaler interfaces.

* Fixes Support for expression Names with literal dots in name. Adds new
  function NameNoDotSplit to expression package. This function allows
  you to provide a literal expression Name containing dots. Also adds a
  new method to NameBuilder, AppendName, for joining multiple name path
  components together. Helpful for joining names with literal dots with
  subsequent object path fields.

* Fixes bug with AttributeValue marshaler struct struct tag usage that
  caused TagKey to be ignored if the member had a struct tag with
  `dynamodbav` struct tag. Now both tags will be read as documented,
  with the TagKey struct tag options taking precedence.
@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A feature should be added or improved.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant