Categorygithub.com/gildas/go-core
modulepackage
0.6.0
Repository: https://github.com/gildas/go-core.git
Documentation: pkg.go.dev

# README

go-core

My core stuff with types, code, etc that I use almost everywhere

Slice generics

Contains

You can check if a slice contains a value with Contains method:

slice := []int{1, 2, 3, 4, 5}

fmt.Println(core.Contains(slice, 4)) // true
fmt.Println(core.Contains(slice, 6)) // false

Contains works with all comparable types.

If the slice type is more complex, you can use ContainsWithFunc method:

type User struct {
  ID int
  Name string
}

slice := []User{
  {ID: 1, Name: "John"},
  {ID: 2, Name: "Jane"},
  {ID: 3, Name: "Bob"},
}

fmt.Println(core.ContainsWithFunc(slice, User{Name: "John"}, func(a, b User) bool {
  return a.Name == b.Name
})) // true

If the struct implements the core.Named interface, you can use the EqualNamed method:

fmt.Println(core.ContainsWithFunc(slice, User{Name: "John"}, core.EqualNamed)) // true

Same goes for core.Identifiable and core.StringIdentifiable interfaces.

Find

You can find a value in a slice with Find method:

slice := []int{1, 2, 3, 4, 5}
number, found := core.Find(slice, 4)

Find works with all comparable types.

If the slice type is more complex, you can use FindWithFunc method:

type User struct {
  ID int
  Name string
}

slice := []User{
  {ID: 1, Name: "John"},
  {ID: 2, Name: "Jane"},
  {ID: 3, Name: "Bob"},
}

user, found := core.FindWithFunc(slice, User{Name: "John"}, func(a, b User) bool {
  return a.Name == b.Name
})

If the struct implements the core.Named interface, you can use the MatchNamed method:

fmt.Println(core.FindWithFunc(slice, User{Name: "John"}, core.MatchNamed)) // true

Same goes for core.Identifiable and core.StringIdentifiable interfaces.

EqualSlices

You can check if two slices are equal with EqualSlices method:

slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{1, 2, 3, 4, 5}

fmt.Println(core.EqualSlices(slice1, slice2)) // true

EqualSlices works with all comparable types.

If the slice type is more complex, you can use EqualSlicesWithFunc method:

type User struct {
  ID int
  Name string
}

slice1 := []User{
  {ID: 1, Name: "John"},
  {ID: 2, Name: "Jane"},
  {ID: 3, Name: "Bob"},
}

slice2 := []User{
  {ID: 1, Name: "John"},
  {ID: 2, Name: "Jane"},
  {ID: 3, Name: "Bob"},
}

fmt.Println(core.EqualSlicesWithFunc(slice1, slice2, func(a, b User) bool {
  return a.Name == b.Name
})) // true

Filter

You can filter a slice with Filter method:

slice := []int{1, 2, 3, 4, 5}

fmt.Println(core.Filter(slice, func(element int) bool {
  return element > 3
})) // [4 5]

Join

You can join a slice with Join method:

slice := []int{1, 2, 3, 4, 5}

fmt.Println(core.Join(slice, ",")) // 1,2,3,4,5

If the slice type is more complex, you can use JoinWithFunc method:

type User struct {
  ID int
  Name string
}

slice := []User{
  {ID: 1, Name: "John"},
  {ID: 2, Name: "Jane"},
  {ID: 3, Name: "Bob"},
}

fmt.Println(core.JoinWithFunc(slice, ",", func(element User) string {
  return element.Name
})) // John,Jane,Bob

Map

You can map a slice with Map method:

slice := []int{1, 2, 3, 4, 5}

fmt.Println(core.Map(slice, func(element int) int {
  return element * 2
})) // [2 4 6 8 10]

The returned slice is a new slice, the original slice is not modified.

Reduce

You can reduce a slice with Reduce method:

slice := []int{1, 2, 3, 4, 5}

fmt.Println(core.Reduce(slice, func(accumulator, element int) int {
  return accumulator + element
})) // 15

Sort

You can sort a slice with Sort method:

slice := []int{5, 2, 3, 1, 4}

fmt.Println(core.Sort(slice, func(a, b int) {
  return a < b
})) // [1 2 3 4 5]

The Sort method uses a simple Quick Sort algorithm.

Time and Duration helpers

The core.Time mimics the time.Time and adds JSON serialization support to and from RFC 3339 time strings.

The core.Duration mimics the time.Duration and adds JSON serialization support to and from duration strings. Its core.ParseDuration also understands most of the ISO 8601 duration formats. It marshals to milliseconds. It can unmarshal from milliseconds, GO duration strings, and ISO 8601 duration strings.

Example:

type User struct {
  Name      string
  CreatedAt core.Time
  Duration  core.Duration
}

user := User{
  Name:      "John",
  CreatedAt: core.Now(),
  Duration:  core.Duration(5 * time.Second),
}

data, err := json.Marshal(user)
if err != nil {
  panic(err)
}

fmt.Println(string(data))
// {"Name":"John","CreatedAt":"2021-01-01T00:00:00Z","Duration":"5000"}

string.Replace(string(data), "5000", "PT5S", 1)

var user2 User
err = json.Unmarshal(data, &user2)
if err != nil {
  panic(err)
}
fmt.Println(user2.Duration) // 5s

The core.Timestamp type is an alias for core.Time and it is used to represent timestamps in milliseconds. It marshals into milliseconds and unmarshals from milliseconds (string or integer).

Environment Variable helpers

You can get an environment variable with GetEnvAsX method, where X is one of bool, time.Duration, string, time.Time, url.URL, uuid.UUID, if the environment variable is not set or the conversion fails, the default value is returned.

Example:

// GetEnvAsBool
v := core.GetEnvAsBool("ENV_VAR", false)
// GetEnvAsDuration
v := core.GetEnvAsDuration("ENV_VAR", 5 * time.Second)
// GetEnvAsString
v := core.GetEnvAsString("ENV_VAR", "default")
// GetEnvAsTime
v := core.GetEnvAsTime("ENV_VAR", time.Now())
// GetEnvAsURL
v := core.GetEnvAsURL("ENV_VAR", &url.URL{Scheme: "https", Host: "example.com"})
// GetEnvAsUUID
v := core.GetEnvAsUUID("ENV_VAR", uuid.New())

Notes:

  • GetEnvAsBool returns true if the environment variable is set to true, 1, on or yes, otherwise it returns false. It is also case-insensitive.
  • GetEnvAsDuration accepts any duration string that can be parsed by core.ParseDuration.
  • GetEnvAsTime accepts an RFC 3339 time string.
  • GetEnvAsURL fallback can be a url.URL, a *url.URL, or a string.

Common Interfaces

The core.Identifiable interface is used to represent an object that has an ID in the form of a uuid.UUID.

The core.Nameable interface is used to represent an object that has a name in the form of a string.

The core.IsZeroer interface is used to represent an object that can be checked if it is zero.

The core.GoString interface is used to represent an object that can be converted to a Go string.

HTTP Response helpers

core.RespondWithJSON is a helper function that marshals a payload into an http.ResponseWriter as JSON. It also sets the Content-Type header to application/json.

core.RespondWithHTMLTemplate is a helper function that executes a template on a given data and writes the result into an http.ResponseWriter. It also sets the Content-Type header to text/html.

core.RespondWithError is a helper function that marshals an error into an http.ResponseWriter as JSON. It also sets the Content-Type header to application/json.

Miscelaneous

ExecEvery executes a function every duration:

stop, ping, change := core.ExecEvery(5 * time.Second, func() {
  fmt.Println("ping")
})

time.Sleep(15 * time.Second)
change <- 10 * time.Second
time.Sleep(15 * time.Second)
stop <- true

Notes:

  • stop is a channel that can be used to stop the execution.
  • ping is a channel that can be used to force the execution of the func at any time.
  • change is a channel that can be used to change the execution duration.

FlexInt, FlexInt8, FlexInt16, FlexInt32, FlexInt64 are types that can be unmarshalled from a string or an integer:

type User struct {
  ID core.FlexInt
}

user := User{}
json.Unmarshal([]byte(`{"ID": 1}`), &user)
json.Unmarshal([]byte(`{"ID": "1"}`), &user)

core.Must is a helper function that panics if the error is not nil from a function that returns a value and an error:

func DoSomething() (string, error) {
  return "", errors.New("error")
}

func main() {
  value := core.Must(DoSomething()).(string)
}

core.URL is an alias for url.URL that marshals as a string and unmarshals from a string. When unmarshaling, if the value is nil or empty, the unmarshaled value is nil (it is not considered as an error).

core.UUID is an alias for uuid.UUID that marshals as a string and unmarshals from a string. When unmarshaling, if the value is nil or empty, the unmarshaled value is uuid.Nil (it is not considered as an error).

core.TypeRegistry is a type registry that can be used to unmarshal JSON core.TypeCarrier objects into the correct type:

type User struct {
  ID   uuid.UUID
  Name string
}

func (user User) GetType() string {
  return "user"
}

type Product struct {
  ID   uuid.UUID
  Name string
}

func (product Product) GetType() string {
  return "product"
}

registry := core.NewTypeRegistry()

registry.Add(User{}, Product{})

var user User

err := registry.UnmarshalJSON([]byte(`{"type": "user", "ID": "00000000-0000-0000-0000-000000000000", "Name": "John"}`), &user)
if err != nil {
  panic(err)
}

fmt.Println(user)

Notes:

  • The default JSON property name for the type is type, but it can be changed by adding strings to the UnmarshalJSON method.

# Functions

Atoi convert a string to an int using a fallback if the conversion fails.
Contains checks if a slice contains a value.
ContainsWithFunc checks if a slice contains a value using a custom function.
Date returns a new Date.
DateUTC returns a new Date.
DecodeUUID decodes a UUID from a 22 char long string.
Decorate decorates a struct that can be identified.
DecorateAll decorates all items in a slice of identifiable items.
DecorateWithURL decorates a struct that can be identified with a URL.
EncodeUUID encodes a UUID in a 22 char long string.
EqualIdentifiable compares two values for equality by their Identifier.
RqualNamed compares two values for equality by name.
EqualSlices checks if two slices are equal.
EqualSlicesWithFunc checks if two slices are equal.
EqualStringIdentifiable compares two values for equality by their Identifier.
ExecEvery runs a func as a go routine regularly returns 3 chans: - a chan to stop the time loop, pipe true - a chan to force the job execution on demand - a chan to change the ticker interval the invoked func can modify the interval by piping a new Duration to its given chan the func is executed once before the ticker starts.
Filter filters a slice of items based on a filter function Note: The result is a new slice, the original is not modified Example: // Filter all positive numbers in a slice numbers := Filter(numbers, func(number int) bool { return number > 0 }).
Find finds a value in a slice.
FindWithFunc is a function that finds a value in a slice.
GetEnvAsBool returns the bool value of an environment variable by its name if not present, the fallback value is used.
GetEnvAsDuration returns the time value of an environment variable by its name if not present, the fallback value is used.
GetEnvAsInt returns the int value of an environment variable by its name if not present, the fallback value is used.
GetEnvAsString returns the string value of an environment variable by its name if not present, the fallback value is used.
GetEnvAsTime returns the time value of an environment variable by its name if not present, the fallback value is used.
GetEnvAsURL returns the URL value of an environment variable by its name if not present, the fallback value is used.
No description provided by the author
Join joins a slice of items into a string using a separator.
JoinWithFunc joins a slice of items into a string using a separator.
Map maps a slice of items into a new slice Note: The result is a new slice, the original is not modified Example: // Map all numbers in a slice to their square squares := Map(numbers, func(number int) int { return number * number }).
MapJoin joins two or more maps of the same kind None of the maps are modified, a new map is created.
MatchIdentifiable returns a function that matches an Identifiable value.
MatchNamed returns a function that matches a Named value.
MatchStringIdentifiable returns a function that matches a StringIdentifiable value.
Must panics if there is an error, otherwise returns the given value Example: var myurl = core.Must[*url.URL](url.Parse("https://www.acme.com")).
Now returns the current local time.
NowIn returns the current time in the given location.
NowUTC returns the current UTC time.
ParseDuration parses an ISO8601 duration If the given value is not an ISO8601 duration, returns time.ParseDuration.
ParseTime parses the given string for a Time, if the Time is not UTC it is set in the current location.
ParseTimeIn parses the given string for a Time, if the Time is not UTC it is set in the given location.
Reduce reduces a slice of items into a single value Example: // Sum all numbers in a slice sum := Reduce(numbers, 0, func(sum, number int) int { return sum + number }).
RespondWithError will send a reply with an error as JSON and a HTTP Status code.
RespondWithHTMLTemplate will send a reply with a HTML payload generated from an HTML Template and a HTTP Status code.
RespondWithJSON will send a reply with a JSON payload and a HTTP Status code.
Sort sorts a slice of items using the Quick Sort algorithm Note: The items slice is modified in place.
TimestampFromJSEpoch returns a Timestamp from a JS Epoch.
TimestampNow returns a Timestamp at the time of its call.

# Variables

VERSION is the version of this application.

# Structs

DecoratedResource is a resource that contains a Self link.

# Interfaces

GoString represents object that can give their Go internals as a String.
Identifiable describes that can get their Identifier as a UUID.
IsZeroer is an interface that can be implemented by types that can tell if their value is zero.
Named describes types that can get their Name.
StringIdentifiable describes that can get their Identifier as a string.
TypeCarrier represents object that carries a Type.

# Type aliases

Duration is a placeholder so we can add new funcs to the type.
FlexInt is an int that can be unmashaled from an int or a string (1234 or "1234").
FlexInt16 is an int that can be unmashaled from an int or a string (1234 or "1234").
FlexInt32 is an int that can be unmashaled from an int or a string (1234 or "1234").
FlexInt64 is an int that can be unmashaled from an int or a string (1234 or "1234").
FlexInt8 is an int that can be unmashaled from an int or a string (1234 or "1234").
Time is a placeholder so we can add new funcs to the type.
Timestamp converts Unix Epoch to/from time.Time.
TypeRegistry contains a map of identifier vs Type.
URL is a placeholder so we can add new funcs to the type.
No description provided by the author