Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions conv/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,3 +321,33 @@ func PasswordValue(v *strfmt.Password) strfmt.Password {

return *v
}

// Currency returns a pointer to the [strfmt.Currency] value passed in.
func Currency(v strfmt.Currency) *strfmt.Currency {
return &v
}

// CurrencyValue returns the value of the [strfmt.Currency] pointer passed in or
// the default value if the pointer is nil.
func CurrencyValue(v *strfmt.Currency) strfmt.Currency {
if v == nil {
return strfmt.Currency{}
}

return *v
}

// Country returns a pointer to the [strfmt.Country] value passed in.
func Country(v strfmt.Country) *strfmt.Country {
return &v
}

// CountryValue returns the value of the [strfmt.Country] pointer passed in or
// the default value if the pointer is nil.
func CountryValue(v *strfmt.Country) strfmt.Country {
if v == nil {
return strfmt.Country{}
}

return *v
}
173 changes: 173 additions & 0 deletions country.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could have updated to use 2026, even if I know copyright date ranges are usually misunderstood

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we've been there already, don't recall it?

// SPDX-License-Identifier: Apache-2.0

package strfmt

import (
"database/sql/driver"
"encoding/json"
"fmt"

"github.com/go-openapi/strfmt/internal/countries"
)

// Country represents an ISO 3166 country alpha-3 or alpha-2 code as a string format.
//
// swagger:strfmt country.
type Country struct {
countries.Country

l int
}

const (
alpha2Len = 2
alpha3Len = 3
)

// IsCountry checks if a string is a valid ISO 3166 country format.
func IsCountry(str string) bool {
_, err := ParseCountry(str)

return err == nil
}

// ParseCountry parses a string that represents a valid [Country].
func ParseCountry(str string) (Country, error) {
l := len(str)
switch l {
case alpha3Len:
c, ok := countries.CountriesISO3[str]
if !ok {
return Country{}, fmt.Errorf("unrecognized strfmt.Country %q: %w", str, ErrFormat)
}

return Country{Country: c, l: alpha3Len}, nil
case alpha2Len:
c, ok := countries.CountriesISO2[str]
if !ok {
return Country{}, fmt.Errorf("unrecognized strfmt.Country %q: %w", str, ErrFormat)
}

return Country{Country: c, l: alpha2Len}, nil
default:
return Country{}, fmt.Errorf("invalid length for strfmt.Country in: %q: %w", str, ErrFormat)
}
}

// MarshalText returns this instance into text.
func (u Country) MarshalText() ([]byte, error) {
return []byte(u.String()), nil
}

// UnmarshalText hydrates this instance from text.
func (u *Country) UnmarshalText(data []byte) error { // validation is performed later on
c, err := ParseCountry(string(data))
if err != nil {
return err
}

*u = c

return nil
}

// Scan read a value from a database driver.
func (u *Country) Scan(raw any) error {
switch v := raw.(type) {
case []byte:
c, err := ParseCountry(string(v))
if err != nil {
return err
}
*u = c
case string:
c, err := ParseCountry(v)
if err != nil {
return err
}
*u = c
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Country from: %#v: %w", v, ErrFormat)
}

return nil
}

// Value converts a value to a database driver value.
func (u Country) Value() (driver.Value, error) {
return driver.Value(u.String()), nil
}

func (u Country) String() string {
switch u.l {
case alpha3Len:
return u.ISOAlpha3
case alpha2Len:
return u.ISOAlpha2
default:
return ""
}
}
Comment on lines +102 to +111

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see you use String everywhere (Marshal and others), which makes unserializaton and serialization stable

But as a user, when you get a country with FRA or FR and send it to your lib, I would expect to get France

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name "France" is resolved in the embedded type, but not used for wire-serialization

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name "France" is resolved in the embedded type, but not used for wire-serialization

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so you have to use Country.Name

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but why String would return you passed to the lib.

Maybe you should mention the lib is is made for being idempotent. It might be cleaer why FRA is returned when you pass FRA, either in string, JSON


// MarshalJSON returns the [Country] as JSON.
func (u Country) MarshalJSON() ([]byte, error) {
return json.Marshal(u.String())
}

// UnmarshalJSON sets the [Country] from JSON.
func (u *Country) UnmarshalJSON(data []byte) error {
if string(data) == jsonNull {
return nil
}
var ustr string
if err := json.Unmarshal(data, &ustr); err != nil {
return err
}

c, err := ParseCountry(ustr)
if err != nil {
return err
}

*u = c

return nil
}

// DeepCopyInto copies the receiver and writes its value into out.
func (u *Country) DeepCopyInto(out *Country) {
*out = *u
}

// DeepCopy copies the receiver into a new [Country].
func (u *Country) DeepCopy() *Country {
if u == nil {
return nil
}

out := new(Country)
u.DeepCopyInto(out)

return out
}

// GobEncode implements the gob.GobEncoder interface.
func (u Country) GobEncode() ([]byte, error) {
return u.MarshalText()
}

// GobDecode implements the gob.GobDecoder interface.
func (u *Country) GobDecode(data []byte) error {
return u.UnmarshalText(data)
}

// MarshalBinary implements the encoding.[encoding.BinaryMarshaler] interface.
func (u Country) MarshalBinary() ([]byte, error) {
return u.MarshalText()
}

// UnmarshalBinary implements the encoding.[encoding.BinaryUnmarshaler] interface.
func (u *Country) UnmarshalBinary(data []byte) error {
return u.UnmarshalText(data)
}
57 changes: 57 additions & 0 deletions country_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0

package strfmt

import (
"iter"
"slices"
"testing"

"github.com/go-openapi/testify/v2/require"
)

func TestCountry(t *testing.T) {
for tc := range countryCases() {
t.Run(tc.Desc, func(t *testing.T) {
if tc.Valid {
require.TrueT(t, IsCountry(tc.Input))

cur, err := ParseCountry(tc.Input)
require.NoError(t, err)

b, err := cur.MarshalText()
require.NoError(t, err)
require.NotEmpty(t, b)

var other Country
require.NoError(t, other.UnmarshalText(b))

require.EqualT(t, cur.String(), other.String())

return
}

require.FalseT(t, IsCountry(tc.Input))
})
}
}

type countryCase struct {
Desc string
Input string
Valid bool
}

func countryCases() iter.Seq[countryCase] {
return slices.Values([]countryCase{
{Desc: "USA", Input: "USA", Valid: true},
{Desc: "FR-alpha-2", Input: "FR", Valid: true},
{Desc: "GBR-alpha-3", Input: "GBR", Valid: true},
{Desc: "unknown-alpha-2", Input: "FF", Valid: false},
{Desc: "unknown-alpha-3", Input: "XYZ", Valid: false},
{Desc: "invalid (empty)", Input: "", Valid: false},
{Desc: "invalid (1)", Input: "X", Valid: false},
{Desc: "invalid (4)", Input: "ABCD", Valid: false},
})
}
Loading
Loading