Skip to content

Commit

Permalink
feat: add default:update
Browse files Browse the repository at this point in the history
  • Loading branch information
jmattheis committed Dec 13, 2024
1 parent 23b6fc6 commit a8a6bdc
Show file tree
Hide file tree
Showing 32 changed files with 774 additions and 77 deletions.
1 change: 1 addition & 0 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type MethodContext struct {
Conf *config.Method
FieldsTarget string
OutputPackagePath string
UseConstructor bool
Signature xtype.Signature
TargetType *xtype.Type
HasMethod func(*MethodContext, types.Type, types.Type) bool
Expand Down
3 changes: 2 additions & 1 deletion builder/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import (
)

func buildTargetVar(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, source, target *xtype.Type, errPath ErrorPath) ([]jen.Code, *jen.Statement, *Error) {
if ctx.Conf.Constructor == nil ||
if !ctx.UseConstructor ||
!types.Identical(ctx.Conf.Source.T, source.T) ||
!types.Identical(ctx.Conf.Target.T, target.T) {
name := ctx.Name(target.ID())
variable := jen.Var().Id(name).Add(target.TypeAsJen())
ctx.SetErrorTargetVar(jen.Id(name))
return []jen.Code{variable}, jen.Id(name), nil
}
ctx.UseConstructor = false

callTarget := target
toPointer := target.Pointer && !ctx.Conf.Constructor.Target.Pointer
Expand Down
83 changes: 63 additions & 20 deletions builder/pointer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,34 @@ func (*Pointer) Matches(_ *MethodContext, source, target *xtype.Type) bool {
// Build creates conversion source code for the given source and target type.
func (p *Pointer) Build(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, source, target *xtype.Type, errPath ErrorPath) ([]jen.Code, *xtype.JenID, *Error) {
ctx.SetErrorTargetVar(jen.Nil())
if ctx.UseConstructor && ctx.Conf.DefaultUpdate {
buildStmt, valueVar, err := buildTargetVar(gen, ctx, sourceID, source, target, errPath)
if err != nil {
return nil, nil, err
}

Check warning on line 23 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L22-L23

Added lines #L22 - L23 were not covered by tests

stmt, err := gen.Assign(ctx, AssignOf(jen.Parens(jen.Op("*").Add(valueVar))), sourceID.Deref(source), source.PointerInner, target.PointerInner, errPath)
if err != nil {
return nil, nil, err.Lift(&Path{
SourceID: "*",
SourceType: source.PointerInner.String,
TargetID: "*",
TargetType: target.PointerInner.String,
})
}

Check warning on line 33 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L27-L33

Added lines #L27 - L33 were not covered by tests

buildStmt = append(buildStmt, jen.If(sourceID.Code.Clone().Op("!=").Nil()).Block(stmt...))

return buildStmt, xtype.VariableID(valueVar), nil
}

return BuildByAssign(p, gen, ctx, sourceID, source, target, errPath)
}

func (*Pointer) Assign(gen Generator, ctx *MethodContext, assignTo *AssignTo, sourceID *xtype.JenID, source, target *xtype.Type, errPath ErrorPath) ([]jen.Code, *Error) {
ctx.SetErrorTargetVar(jen.Nil())

valueSourceID := jen.Op("*").Add(sourceID.Code.Clone())
if !source.PointerInner.Basic {
valueSourceID = jen.Parens(valueSourceID)
}

innerID := xtype.OtherID(valueSourceID)
innerID.ParentPointer = sourceID
nextBlock, id, err := gen.Build(
ctx, innerID, source.PointerInner, target.PointerInner, errPath)
nextBlock, id, err := gen.Build(ctx, sourceID.Deref(source), source.PointerInner, target.PointerInner, errPath)
if err != nil {
return nil, err.Lift(&Path{
SourceID: "*",
Expand Down Expand Up @@ -62,19 +75,30 @@ func (*SourcePointer) Matches(ctx *MethodContext, source, target *xtype.Type) bo

// Build creates conversion source code for the given source and target type.
func (s *SourcePointer) Build(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, source, target *xtype.Type, path ErrorPath) ([]jen.Code, *xtype.JenID, *Error) {
if ctx.UseConstructor && ctx.Conf.DefaultUpdate {
buildStmt, valueVar, err := buildTargetVar(gen, ctx, sourceID, source, target, path)
if err != nil {
return nil, nil, err
}

Check warning on line 82 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L78-L82

Added lines #L78 - L82 were not covered by tests

stmt, err := gen.Assign(ctx, AssignOf(valueVar), sourceID.Deref(source), source.PointerInner, target, path)
if err != nil {
return nil, nil, err.Lift(&Path{
SourceID: "*",
SourceType: source.PointerInner.String,
})
}

Check warning on line 90 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L84-L90

Added lines #L84 - L90 were not covered by tests

buildStmt = append(buildStmt, jen.If(sourceID.Code.Clone().Op("!=").Nil()).Block(stmt...))

return buildStmt, xtype.VariableID(valueVar), nil

Check warning on line 94 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L92-L94

Added lines #L92 - L94 were not covered by tests
}

return BuildByAssign(s, gen, ctx, sourceID, source, target, path)
}

func (*SourcePointer) Assign(gen Generator, ctx *MethodContext, assignTo *AssignTo, sourceID *xtype.JenID, source, target *xtype.Type, path ErrorPath) ([]jen.Code, *Error) {
valueSourceID := jen.Op("*").Add(sourceID.Code.Clone())
if !source.PointerInner.Basic {
valueSourceID = jen.Parens(valueSourceID)
}

innerID := xtype.OtherID(valueSourceID)
innerID.ParentPointer = sourceID

nextInner, nextID, err := gen.Build(ctx, innerID, source.PointerInner, target, path)
nextInner, nextID, err := gen.Build(ctx, sourceID.Deref(source), source.PointerInner, target, path)
if err != nil {
return nil, err.Lift(&Path{
SourceID: "*",
Expand Down Expand Up @@ -102,18 +126,37 @@ func (*TargetPointer) Matches(_ *MethodContext, source, target *xtype.Type) bool
// Build creates conversion source code for the given source and target type.
func (*TargetPointer) Build(gen Generator, ctx *MethodContext, sourceID *xtype.JenID, source, target *xtype.Type, path ErrorPath) ([]jen.Code, *xtype.JenID, *Error) {
ctx.SetErrorTargetVar(jen.Nil())

if ctx.UseConstructor {
buildStmt, valueVar, err := buildTargetVar(gen, ctx, sourceID, source, target, path)
if err != nil {
return nil, nil, err
}

Check warning on line 134 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L131-L134

Added lines #L131 - L134 were not covered by tests

stmt, err := gen.Assign(ctx, AssignOf(jen.Parens(jen.Op("*").Add(valueVar))), sourceID, source, target.PointerInner, path)
if err != nil {
return nil, nil, err.Lift(&Path{
TargetID: "*",
TargetType: target.PointerInner.String,
})
}

Check warning on line 142 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L136-L142

Added lines #L136 - L142 were not covered by tests

buildStmt = append(buildStmt, stmt...)

return buildStmt, xtype.VariableID(valueVar), nil

Check warning on line 146 in builder/pointer.go

View check run for this annotation

Codecov / codecov/patch

builder/pointer.go#L144-L146

Added lines #L144 - L146 were not covered by tests
}

stmt, id, err := gen.Build(ctx, sourceID, source, target.PointerInner, path)
if err != nil {
return nil, nil, err.Lift(&Path{
SourceID: "*",
SourceType: source.String,
TargetID: "*",
TargetType: target.PointerInner.String,
})
}

pstmt, nextID := id.Pointer(target.PointerInner, ctx.Name)
stmt = append(stmt, pstmt...)

return stmt, nextID, nil
}

Expand Down
6 changes: 3 additions & 3 deletions config/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Common struct {
SkipCopySameType bool
UseZeroValueOnPointerInconsistency bool
UseUnderlyingTypeMethods bool
DefaultUpdate bool
ArgContextRegex *regexp.Regexp
Enum enum.Config
}
Expand All @@ -45,14 +46,13 @@ func parseCommon(c *Common, cmd, rest string) (fieldSetting bool, err error) {
c.IgnoreStructZeroValueField = c.IgnoreBasicZeroValueField
c.IgnoreNillableZeroValueField = c.IgnoreBasicZeroValueField
case "update:ignoreZeroValueField:basic":
fieldSetting = true
c.IgnoreBasicZeroValueField, err = parseBool(rest)
case "update:ignoreZeroValueField:struct":
fieldSetting = true
c.IgnoreStructZeroValueField, err = parseBool(rest)
case "update:ignoreZeroValueField:nillable":
fieldSetting = true
c.IgnoreNillableZeroValueField, err = parseBool(rest)
case "default:update":
c.DefaultUpdate, err = parseBool(rest)
case "matchIgnoreCase":
fieldSetting = true
c.MatchIgnoreCase, err = parseBool(rest)
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import GH from './GH.vue';
## unreleased

- Fix not setting `nil` on map when value is `nil`. <GH issue="173" pr="175"/>
- Add [`default:update`](/reference/default.md#default-update-yes-no) <GH issue="171" pr="175"/>

## v1.6.0

Expand Down
26 changes: 26 additions & 0 deletions docs/reference/default.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Setting: default

[[toc]]

## default [PACKAGE:]FUNC

`default [PACKAGE:]FUNC` can be defined as [method
comment](./define-settings.md#method).

Expand All @@ -18,3 +22,25 @@ package of the conversion method is used.
<<< @../../example/default/input.go
<<< @../../example/default/generated/generated.go [generated/generated.go]
:::

## default:update [yes|no]

`default:update [yes,no]` is a
[boolean setting](./define-settings.md#boolean) and can be defined as
[CLI argument](./define-settings.md#cli),
[conversion comment](./define-settings.md#conversion) or
[method comment](./define-settings.md#method). This setting is
[inheritable](./define-settings.md#inheritance).

> [!WARNING]
> If enabled, goverter requires you to return a **non nil** value in the
> `default` `FUNC`.

If _enabled_ goverter will update the existing instance returned by the
`default` `FUNC`.

::: code-group
<<< @../../example/default-update/input.go
<<< @../../example/default-update/generated/generated.go [generated/generated.go]
:::
20 changes: 20 additions & 0 deletions example/default-update/generated/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions example/default-update/input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package example

// goverter:converter
// goverter:default:update
type Converter interface {
// goverter:default NewOutput
Convert(*Input) *Output
}

type Input struct {
Age int
Name *string
}
type Output struct {
Age int
Name *string
}

func NewOutput() *Output {
name := "jmattheis"
return &Output{Age: 42, Name: &name}
}
5 changes: 1 addition & 4 deletions example/default/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,5 @@ type Output struct {

func NewOutput() *Output {
name := "jmattheis"
return &Output{
Age: 42,
Name: &name,
}
return &Output{Age: 42, Name: &name}
}
1 change: 1 addition & 0 deletions generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func (g *generator) buildMethod(genMethod *generatedMethod, context map[string]*
Signature: genMethod.Signature,
HasMethod: g.hasMethod,
OutputPackagePath: g.conf.OutputPackagePath,
UseConstructor: genMethod.Constructor != nil,
}

var targetAssign *jen.Statement
Expand Down
47 changes: 47 additions & 0 deletions scenario/default_on_basic_pointer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
input:
input.go: |
package execution
// goverter:converter
type Converter interface {
// goverter:default NewStringP
One(source string) *string
// goverter:default NewStringP
Two(source *string) *string
// goverter:default NewString
// goverter:useZeroValueOnPointerInconsistency
Three(source *string) string
}
func NewStringP() *string { return nil }
func NewString() string { return "" }
success:
- generated/generated.go: |
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
package generated
import execution "github.com/jmattheis/goverter/execution"
type ConverterImpl struct{}
func (c *ConverterImpl) One(source string) *string {
pString := source
return &pString
}
func (c *ConverterImpl) Three(source *string) string {
xstring := execution.NewString()
if source != nil {
xstring = *source
}
return xstring
}
func (c *ConverterImpl) Two(source *string) *string {
pString := execution.NewStringP()
if source != nil {
xstring := *source
pString = &xstring
}
return pString
}
33 changes: 22 additions & 11 deletions scenario/default_on_pointer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@ input:
package execution
// goverter:converter
type Converter interface {
type Default interface {
// goverter:default NewOutputWithDefaults
Convert(source *Input) (*Output, error)
}
type Input struct {
Name string
}
type Output struct {
Name string
// goverter:converter
type Update interface {
// goverter:default NewOutputWithDefaults
// goverter:default:update
Update(source *Input) (*Output, error)
}
type Input struct { Name string }
type Output struct { Name string }
func NewOutputWithDefaults() *Output {
return &Output{
Name: "string",
}
return &Output{ Name: "string" }
}
success:
- generated/generated.go: |
Expand All @@ -27,9 +28,9 @@ success:
import execution "github.com/jmattheis/goverter/execution"
type ConverterImpl struct{}
type DefaultImpl struct{}
func (c *ConverterImpl) Convert(source *execution.Input) (*execution.Output, error) {
func (c *DefaultImpl) Convert(source *execution.Input) (*execution.Output, error) {
pExecutionOutput := execution.NewOutputWithDefaults()
if source != nil {
var executionOutput execution.Output
Expand All @@ -38,3 +39,13 @@ success:
}
return pExecutionOutput, nil
}
type UpdateImpl struct{}
func (c *UpdateImpl) Update(source *execution.Input) (*execution.Output, error) {
pExecutionOutput := execution.NewOutputWithDefaults()
if source != nil {
(*pExecutionOutput).Name = (*source).Name
}
return pExecutionOutput, nil
}
Loading

0 comments on commit a8a6bdc

Please sign in to comment.