A Go package that provides custom database fields and JSON-friendly types
2025-10-03 09:37:36 +03:00
currency.go types not anar-types 2025-09-29 17:34:30 +03:00
decimal.go add decimal type 2025-10-02 09:53:20 +03:00
dimension.go types not anar-types 2025-09-29 17:34:30 +03:00
email.go move email type to new file 2025-10-03 09:34:23 +03:00
file.go move file type to new file 2025-10-03 09:18:02 +03:00
geo_location.go types not anar-types 2025-09-29 17:34:30 +03:00
go.mod add password type 2025-09-30 10:22:25 +03:00
go.sum add password type 2025-09-30 10:22:25 +03:00
json.go move json type to new file 2025-10-03 09:25:23 +03:00
password.go add new password func 2025-10-02 16:21:08 +03:00
phone.go types not anar-types 2025-09-29 17:34:30 +03:00
README.md update redeme file 2025-10-03 09:37:14 +03:00
string_array.go move string_array to new file 2025-10-03 09:36:21 +03:00
time.go move time type to new file 2025-10-03 09:32:06 +03:00

anar-types

A Go package that provides custom database fields and JSON-friendly types for common application needs.
These fields integrate smoothly with GORM, the database/sql driver, and standard Go encoding/json.

Features

  • FileField Expands relative paths into full URLs using APP_URL env variable.
  • JSONField Stores map[string]interface{} as JSON in DB.
  • StringArray Stores []string as JSON in DB.
  • TimeField Nullable timestamp with ISO8601 (RFC3339) JSON serialization.
  • EmailField RFC5322-compliant email validation and safe DB storage.
  • PhoneField Validated phone numbers in E.164 format using libphonenumber.
  • GeoLocationField Latitude, longitude, and optional altitude with validation.
  • DimensionField Width, height, depth, and unit (cm, m, in, ft).
  • CurrencyField Money values with ISO4217 currency validation.
  • PasswordField Secure password storage with bcrypt hashing, strength validation, JSON masking, and comparison helpers.
  • Decimal High-precision fixed-point decimal with math operations, rounding, JSON/DB integration, and string/float conversions.

Installation

go get codeberg.org/anarproject/anar-types

Usage

FileField

type User struct {
    Avatar types.FileField `json:"avatar"`
}

// If APP_URL="https://example.com"
// and Avatar="uploads/img.png"
// JSON ? { "avatar": "https://example.com/uploads/img.png" }

JSONField

type Settings struct {
    Config types.JSONField `json:"config"`
}

settings := Settings{
    Config: types.JSONField{"theme": "dark", "lang": "en"},
}

StringArray

type Post struct {
    Tags types.StringArray `json:"tags"`
}

post := Post{Tags: []string{"go", "gorm", "json"}}

TimeField

now := time.Now()
t := types.NewTimeField(now)
jsonBytes, _ := json.Marshal(t)
// ? "2025-09-29T04:00:00Z"

EmailField

var email types.EmailField
email.Scan("user@example.com") // ? valid
email.Scan("bad-email")        // ? error

PhoneField

var phone types.PhoneField
_ = phone.UnmarshalJSON([]byte(`"+14155552671"`))
// phone ? "+14155552671"

fmt.Println(phone.National()) // (415) 555-2671
fmt.Println(phone.Region())   // US

GeoLocationField

geo := types.GeoLocationField{
    Latitude:  37.7749,
    Longitude: -122.4194,
    Altitude:  15.5,
}
jsonBytes, _ := json.Marshal(geo)
// ? {"lat":37.7749,"lng":-122.4194,"alt":15.5}

DimensionField

dim := types.DimensionField{
    Width:  100,
    Height: 200,
    Depth:  50,
    Unit:   "cm",
}
jsonBytes, _ := json.Marshal(dim)
// ? {"width":100,"height":200,"depth":50,"unit":"cm"}

CurrencyField

price := types.CurrencyField{
    Amount:   99.99,
    Currency: "USD",
}
jsonBytes, _ := json.Marshal(price)
// ? {"amount":99.99,"currency":"USD"}

PasswordField

type User struct {
    Email    types.EmailField    `json:"email"`
    Password types.PasswordField `json:"password"`
}

// Create new password
pwd, err := types.NewPassword("MyS3cretPass!")
if err != nil {
    panic(err)
}
user := User{Email: "user@example.com", Password: pwd}

// Marshal to JSON
jsonBytes, _ := json.Marshal(user)
// Output: { "email":"user@example.com", "password":"********" }

// Compare passwords
isValid := user.Password.ComparePassword("MyS3cretPass!")
fmt.Println(isValid) // true

Decimal

// Create decimals
d1, _ := types.NewFromString("10.50")
d2 := types.NewFromInt(2)
d3 := types.NewFromFloat(3.14159)

// Arithmetic
sum := d1.Add(d2)       // 12.50
diff := d1.Sub(d2)      // 8.50
prod := d1.Mul(d3)      // 32.986...
quot, _ := d1.Div(d2)   // 5.25

// Comparison
fmt.Println(d1.GreaterThan(d2)) // true
fmt.Println(d1.Equal(d2))       // false

// Rounding
rounded := d3.Round(2) // 3.14

// Square root
sqrt, _ := d1.Sqrt()   // ~3.240370349

// Conversion
fmt.Println(d1.String()) // "10.5"
f64, _ := d1.Float64()   // 10.5
i64 := d1.Int64()        // 10

// JSON
jsonBytes, _ := json.Marshal(d1)
// ? "10.5"

// Database (GORM model)
type Invoice struct {
    ID     uint
    Amount types.Decimal `json:"amount"`
}

Environment Variables

  • APP_URL ? Used by FileField to build absolute file URLs.

    • Example: APP_URL=https://example.com

Database Integration

All custom types implement:

  • driver.Valuer ? For writing to the database.
  • sql.Scanner ? For reading from the database.

That means you can use them directly in GORM models.

type Product struct {
    ID       uint
    Name     string
    Price    types.CurrencyField
    Size     types.DimensionField
    Location types.GeoLocationField
}

License

This package is licensed under the GNU Lesser General Public License (LGPL) v3.