Skip to content

sonirico/vago

Repository files navigation

a golang gopher napping in the beach

vago

The ultimate toolkit for vaGo developers. A comprehensive collection of functions, data structures, and utilities designed to enhance productivity and code quality with no learning curve and less effort.

Go Report Card Go Reference License: MIT Release

📖 View full documentation and examples on pkg.go.dev →

Workspace Architecture

This project leverages Go workspaces to provide isolated dependencies for each module. This means:

  • Lightweight imports: When you import fp or streams, you won't download database drivers or logging dependencies
  • Modular design: Each module (db, lol, num) maintains its own go.mod with specific dependencies
  • Zero bloat: Use only what you need without carrying unnecessary dependencies
  • Fast builds: Smaller dependency graphs lead to faster compilation and smaller binaries

Example: Importing github.com/sonirico/vago/fp will only pull functional programming utilities, not database connections or logging frameworks.

Modules

Table of Contents

🔀 Cond

Generic conditional operators and ternary expressions with type safety.

Functions

cond If

Example demonstrates basic usage of If with strings

Code
func ExampleIf() {
	result := If(true, "yes", "no")
	fmt.Println(result)
	// Output: yes
}

⬆️ Back to Top


cond IfFunc

Example demonstrates lazy evaluation with IfFunc

Code
func ExampleIfFunc() {
	// This avoids expensive computation if not needed
	result := IfFunc(true,
		func() string { return "computed true" },
		func() string { return "expensive computation" },
	)
	fmt.Println(result)
	// Output: computed true
}

⬆️ Back to Top


cond IfPtr

Example demonstrates IfPtr with pointers

Code
func ExampleIfPtr() {
	valueA := "option A"
	valueB := "option B"

	result := IfPtr(true, &valueA, &valueB)
	fmt.Println(*result)
	// Output: option A
}

⬆️ Back to Top


cond If_false

Example demonstrates If with different condition

Code
func ExampleIf_false() {
	result := If(false, "yes", "no")
	fmt.Println(result)
	// Output: no
}

⬆️ Back to Top


cond If_integers

Example demonstrates If with integers

Code
func ExampleIf_integers() {
	age := 25
	category := If(age >= 18, "adult", "minor")
	fmt.Println(category)
	// Output: adult
}

⬆️ Back to Top


cond OrDefault

Example demonstrates OrDefault

Code
func ExampleOrDefault() {
	// Get value if condition is true, otherwise zero value
	result := OrDefault(true, "has value")
	fmt.Println(result)

	result = OrDefault(false, "has value")
	fmt.Println(result)
	// Output:
	// has value
	//
}

⬆️ Back to Top


⬆️ Back to Top


🗃️ Db

Package db provides a unified set of abstractions, interfaces, and utilities for database access, transaction management, migrations, and efficient bulk operations across multiple backends.

Features:

  • Backend-agnostic interfaces for SQL (Postgres, ClickHouse), MongoDB, and Redis.
  • Context and transaction management with hooks for after-commit actions.
  • Executor interfaces for read-only, read-write, and transactional operations.
  • Bulk DML helpers: efficient bulk insert, update, and upsert with conflict handling.
  • Migration helpers for Postgres and ClickHouse using golang-migrate.
  • Type utilities for nullable JSON, array types, and custom scanning.
  • Common error types and helpers for consistent error handling.
  • Query helpers for generic, type-safe data access patterns.

Main Interfaces:

  • Handler, Querier, Tx, Result, Rows, Row: Abstract over database drivers.
  • Context: Extends context.Context with database query and transaction hooks.
  • Executor, ExecutorRO, ExecutorRW: Transactional execution patterns.
  • Bulkable, BulkableRanger: Bulk DML abstractions.

Backend Adapters:

  • db_pgx.go: Postgres (pgx) support
  • db_clickhouse.go: ClickHouse support
  • db_mongo.go: MongoDB support
  • db_redis.go: Redis support

Utilities:

  • utils_bulk_insert.go, utils_bulk_update.go, utils_bulk_upsert.go: Bulk DML
  • utils_in_clause.go, utils_order_clause.go, utils_query.go: Query helpers
  • types.go: NullJSON, NullJSONArray, and more
  • errors.go: Common error values and helpers
  • migrate.go, migrations_postgres.go, migrations_clickhouse.go: Migration helpers

Example:

import (
    "github.com/sonirico/vago/db"
    "github.com/sonirico/vago/lol"
)

// Setup a logger and a database handler (e.g., pgx)
logger := lol.NewLogger()
handler, _ := db.OpenPgxConn(logger, "postgres://user:pass@localhost/db", false)
executor := db.NewExecutor(logger, handler)

// Run a transactional operation: either all operations succeed, or none are applied
err := executor.DoWithTx(ctx, func(ctx db.Context) error {
    // Multiple DB operations in a transaction
    if _, err := ctx.Querier().ExecContext(ctx, "INSERT INTO users (name) VALUES ($1)", "alice"); err != nil {
        return err
    }
    if _, err := ctx.Querier().ExecContext(ctx, "INSERT INTO accounts (user) VALUES ($1)", "alice"); err != nil {
        return err
    }
    // If any error is returned, all changes are rolled back
    return nil
})

Functions

db BulkInsertSQL

ExampleBulkInsertSQL demonstrates how to use BulkInsertSQL to generate an SQL statement for bulk insertion.

Code
func ExampleBulkInsertSQL() {
	rows := BulkRanger[Bulkable]([]Bulkable{
		&mockBulkable{
			ColsVal: []string{"id", "name", "value"},
			RowVal:  []any{1, "foo", 100},
		},
		&mockBulkable{
			ColsVal: []string{"id", "name", "value"},
			RowVal:  []any{2, "bar", 200},
		},
	})
	query, args, _ := BulkInsertSQL(rows, "my_table")
	fmt.Println("SQL:", normalizeSQL(query))
	fmt.Println("ARGS:", args)
	// Output:
	// SQL: INSERT INTO my_table (id,name,value) VALUES ($1,$2,$3),($4,$5,$6)
	// ARGS: [1 foo 100 2 bar 200]
}

⬆️ Back to Top


db BulkUpdateSQL

ExampleBulkUpdateSQL demonstrates how to use BulkUpdateSQL to generate an SQL statement for bulk updates.

Code
func ExampleBulkUpdateSQL() {
	rows := mockBulkUpdate{
		&mockBulkUpdatable{
			pk:   [2]string{"int", "id"},
			cols: [][2]string{{"int", "value"}, {"text", "name"}},
			vals: []any{1, "foo", 100, "bar"},
		},
		&mockBulkUpdatable{
			pk:   [2]string{"int", "id"},
			cols: [][2]string{{"int", "value"}, {"text", "name"}},
			vals: []any{2, "baz", 200, "qux"},
		},
	}
	query, args, _ := BulkUpdateSQL(rows, "my_table")
	fmt.Println("SQL:", normalizeSQL(query))
	fmt.Println("ARGS:", args)
	// Output:
	// SQL: UPDATE my_table SET value = bulk_update_tmp.value::int,name = bulk_update_tmp.name::text FROM (VALUES ($1::int, $2::int, $3::text), ($4::int, $5::int, $6::text)) as bulk_update_tmp(id, value, name) WHERE my_table.id::int = bulk_update_tmp.id::int
	// ARGS: [1 foo 100 bar 2 baz 200 qux]
}

⬆️ Back to Top


db BulkUpsertSQL

Example for BulkUpsertSQL with update on conflict clause

Code
func ExampleBulkUpsertSQL() {
	rows := BulkRanger[Bulkable]([]Bulkable{
		&mockBulkable{
			PKVal:         []string{"id"},
			UniqueKeysVal: []string{"unique_key"},
			IncludePKVal:  true,
			ColsVal:       []string{"id", "unique_key", "value"},
			RowVal:        []any{1, "abc", 100},
		},
	})
	onConflictUpdate := false
	query, args, _ := BulkUpsertSQL(rows, "my_table", onConflictUpdate)
	fmt.Println("SQL:", normalizeSQL(query))
	fmt.Println("ARGS:", args)

	fmt.Println("--")

	onConflictUpdate = true
	query, args, _ = BulkUpsertSQL(rows, "my_table", onConflictUpdate)
	fmt.Println("SQL:", normalizeSQL(query))
	fmt.Println("ARGS:", args)

	// Output:
	// SQL: INSERT INTO my_table (id,unique_key,value) VALUES ($1,$2,$3) ON CONFLICT (unique_key) DO NOTHING RETURNING id,unique_key,value
	// ARGS: [1 abc 100]
	// --
	// SQL: INSERT INTO my_table (id,unique_key,value) VALUES ($1,$2,$3) ON CONFLICT (unique_key) DO UPDATE SET id = EXCLUDED.id,unique_key = EXCLUDED.unique_key,value = EXCLUDED.value RETURNING id,unique_key,value
	// ARGS: [1 abc 100]
}

⬆️ Back to Top


db Executor

Example for Do and DoWithTx usage with a database service and context.

Code
func ExampleExecutor() {
	db, mock, _ := sqlmock.New(
		sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
	defer db.Close()
	log := lol.ZeroTestLogger

	// Setup mock expectations
	mock.ExpectQuery("SELECT 1;").
		WillReturnRows(sqlmock.NewRows([]string{"n"}).AddRow(1))

	ex := newDatabaseSqlExecutor(log, db)

	err := ex.Do(context.Background(), func(ctx Context) error {
		var n int
		return ctx.Querier().
			QueryRowContext(ctx, "SELECT 1;").Scan(&n)
	})
	fmt.Println("Do error:", err)

	mock.ExpectBegin()
	mock.ExpectQuery("SELECT 2;").
		WillReturnRows(sqlmock.NewRows([]string{"n"}).AddRow(2))
	mock.ExpectCommit()

	err = ex.DoWithTx(context.Background(), func(ctx Context) error {
		var n int
		return ctx.Querier().QueryRowContext(ctx, "SELECT 2;").Scan(&n)
	})
	fmt.Println("DoWithTx error:", err)

	// Output:
	// Do error: <nil>
	// DoWithTx error: <nil>
}

⬆️ Back to Top


db In

ExampleIn demonstrates how to use the In function to generate an SQL IN clause and its arguments.

Code
func ExampleIn() {
	args := []any{"foo"}
	inArgs := []int{1, 2, 3}
	s, a := In(args, inArgs)
	fmt.Println(s)
	fmt.Println(a)
	// Output:
	// ($2,$3,$4)
	// [foo 1 2 3]
}

⬆️ Back to Top


db OrderBy_usage

ExampleOrderBy_usage demonstrates how to use OrderBy types to generate SQL ORDER BY clauses.

Code
func ExampleOrderBy_usage() {
	fmt.Println(OrderASC.FullClause("foo"))
	fmt.Println(OrderDESC.FullClause("foo"))
	// Output:
	//  ORDER BY foo ASC
	//  ORDER BY foo DESC
}

⬆️ Back to Top


⬆️ Back to Top


🪾 Ent

Package ent provides utilities for managing environment variables in a type-safe manner.

Functions

ent Bool

ExampleBool demonstrates how to retrieve boolean environment variables with various true/false representations.

Code
func ExampleBool() {
	// Set environment variable
	os.Setenv("DEBUG", "true")
	defer os.Unsetenv("DEBUG")

	debug := Bool("DEBUG", false)
	fmt.Println(debug)
	// Output:
	//
	// true
}

⬆️ Back to Top


ent CondStrOrPanic

ExampleCondStrOrPanic demonstrates how to conditionally retrieve environment variables with panic on missing values.

Code
func ExampleCondStrOrPanic() {
	// Set environment variable
	os.Setenv("DEBUG_MODE", "true")
	defer os.Unsetenv("DEBUG_MODE")

	// Get value only if condition is true
	debugMode := CondStrOrPanic(true, "DEBUG_MODE")
	fmt.Println(debugMode)

	// Returns empty string if condition is false
	emptyValue := CondStrOrPanic(false, "DEBUG_MODE")
	fmt.Println(emptyValue)
	// Output:
	//
	// true
	//
}

⬆️ Back to Top


ent Contains

ExampleContains demonstrates how to check if a value exists in a slice of strings.

Code
func ExampleContains() {
	fruits := []string{"apple", "banana", "cherry"}

	hasBanana := contains(fruits, "banana")
	fmt.Println(hasBanana)

	hasOrange := contains(fruits, "orange")
	fmt.Println(hasOrange)
	// Output:
	//
	// true
	// false
}

⬆️ Back to Top


ent Duration

ExampleDuration demonstrates how to retrieve time.Duration environment variables with fallback values.

Code
func ExampleDuration() {
	// Set environment variable
	os.Setenv("REQUEST_TIMEOUT", "30s")
	defer os.Unsetenv("REQUEST_TIMEOUT")

	timeout := Duration("REQUEST_TIMEOUT", 10*time.Second)
	fmt.Println(timeout)
	// Output:
	//
	// 30s
}

⬆️ Back to Top


ent Enum

ExampleEnum demonstrates how to retrieve environment variables with validation against allowed values.

Code
func ExampleEnum() {
	// Set environment variable
	os.Setenv("ENV", "staging")
	defer os.Unsetenv("ENV")

	env := Enum("ENV", "dev", "dev", "staging", "prod")
	fmt.Println(env)
	// Output:
	//
	// staging
}

⬆️ Back to Top


ent EnumOrPanic

ExampleEnumOrPanic demonstrates how to retrieve required environment variables with validation against allowed values, panicking if invalid.

Code
func ExampleEnumOrPanic() {
	// Set environment variable
	os.Setenv("LOG_LEVEL", "info")
	defer os.Unsetenv("LOG_LEVEL")

	logLevel := EnumOrPanic("LOG_LEVEL", "debug", "info", "warn", "error")
	fmt.Println(logLevel)
	// Output:
	//
	// info
}

⬆️ Back to Top


ent FixedStrOrPanic

ExampleFixedStrOrPanic demonstrates how to retrieve environment variables with length validation.

Code
func ExampleFixedStrOrPanic() {
	// Set environment variable with exact length
	os.Setenv("API_KEY", "abc123")
	defer os.Unsetenv("API_KEY")

	// Get value with length validation
	apiKey := FixedStrOrPanic("API_KEY", 6)
	fmt.Println(apiKey)
	// Output:
	//
	// abc123
}

⬆️ Back to Top


ent Float64

ExampleFloat64 demonstrates how to retrieve float64 environment variables with fallback values.

Code
func ExampleFloat64() {
	// Set environment variable
	os.Setenv("PRICE", "19.99")
	defer os.Unsetenv("PRICE")

	price := Float64("PRICE", 0.0)
	fmt.Println(price)
	// Output:
	//
	// 19.99
}

⬆️ Back to Top


ent Get

ExampleGet demonstrates how to retrieve environment variables with fallback values.

Code
func ExampleGet() {
	// Set an environment variable
	os.Setenv("APP_NAME", "MyApplication")
	defer os.Unsetenv("APP_NAME")

	// Get existing env var
	appName := Get("APP_NAME", "DefaultApp")
	fmt.Println(appName)

	// Get non-existing env var with fallback
	dbHost := Get("DB_HOST", "localhost")
	fmt.Println(dbHost)
	// Output:
	//
	// MyApplication
	// localhost
}

⬆️ Back to Top


ent Int

ExampleInt demonstrates how to retrieve integer environment variables with fallback values.

Code
func ExampleInt() {
	// Set environment variable
	os.Setenv("WORKER_COUNT", "4")
	defer os.Unsetenv("WORKER_COUNT")

	workers := Int("WORKER_COUNT", 1)
	fmt.Println(workers)
	// Output:
	//
	// 4
}

⬆️ Back to Top


ent Int64

ExampleInt64 demonstrates how to retrieve int64 environment variables with fallback values.

Code
func ExampleInt64() {
	// Set environment variable
	os.Setenv("MAX_CONNECTIONS", "100")
	defer os.Unsetenv("MAX_CONNECTIONS")

	maxConn := Int64("MAX_CONNECTIONS", 50)
	fmt.Println(maxConn)
	// Output:
	//
	// 100
}

⬆️ Back to Top


ent Int64OrPanic

ExampleInt64OrPanic demonstrates how to retrieve required int64 environment variables that panic if missing or invalid.

Code
func ExampleInt64OrPanic() {
	// Set required environment variable
	os.Setenv("PORT", "8080")
	defer os.Unsetenv("PORT")

	port := Int64OrPanic("PORT")
	fmt.Println(port)
	// Output:
	//
	// 8080
}

⬆️ Back to Top


ent IntOrPanic

ExampleIntOrPanic demonstrates how to retrieve required integer environment variables that panic if missing or invalid.

Code
func ExampleIntOrPanic() {
	// Set required environment variable
	os.Setenv("TIMEOUT", "30")
	defer os.Unsetenv("TIMEOUT")

	timeout := IntOrPanic("TIMEOUT")
	fmt.Println(timeout)
	// Output:
	//
	// 30
}

⬆️ Back to Top


ent JSON

ExampleJSON demonstrates how to parse JSON environment variables into Go structs with type safety.

Code
func ExampleJSON() {
	type Config struct {
		Host string `json:"host"`
		Port int    `json:"port"`
	}

	// Set environment variable
	os.Setenv("DB_CONFIG", `{"host":"localhost","port":5432}`)
	defer os.Unsetenv("DB_CONFIG")

	config, err := JSON[Config]("DB_CONFIG", `{"host":"127.0.0.1","port":3306}`)
	if err != nil {
		panic(err)
	}
	fmt.Println(config.Host)
	// Output:
	//
	// localhost
}

⬆️ Back to Top


ent SliceInt

ExampleSliceInt demonstrates how to retrieve integer slice environment variables from comma-separated values.

Code
func ExampleSliceInt() {
	// Set environment variable
	os.Setenv("PORTS", "8080,8081,8082")
	defer os.Unsetenv("PORTS")

	ports := SliceInt("PORTS", []int{3000})
	fmt.Println(len(ports))
	// Output:
	//
	// 3
}

⬆️ Back to Top


ent SliceStr

ExampleSliceStr demonstrates how to retrieve string slice environment variables from comma-separated values.

Code
func ExampleSliceStr() {
	// Set environment variable
	os.Setenv("ALLOWED_HOSTS", "localhost,127.0.0.1,example.com")
	defer os.Unsetenv("ALLOWED_HOSTS")

	hosts := SliceStr("ALLOWED_HOSTS", []string{"localhost"})
	fmt.Println(len(hosts))
	// Output:
	//
	// 3
}

⬆️ Back to Top


ent Str

ExampleStr demonstrates how to retrieve string environment variables with fallback values.

Code
func ExampleStr() {
	// Set environment variable
	os.Setenv("USER_NAME", "john_doe")
	defer os.Unsetenv("USER_NAME")

	username := Str("USER_NAME", "anonymous")
	fmt.Println(username)
	// Output:
	//
	// john_doe
}

⬆️ Back to Top


ent StrOrPanic

ExampleStrOrPanic demonstrates how to retrieve required environment variables that panic if missing.

Code
func ExampleStrOrPanic() {
	// Set required environment variable
	os.Setenv("REQUIRED_CONFIG", "important_value")
	defer os.Unsetenv("REQUIRED_CONFIG")

	// Get required value (panics if missing)
	config := StrOrPanic("REQUIRED_CONFIG")
	fmt.Println(config)
	// Output:
	//
	// important_value
}

⬆️ Back to Top


⬆️ Back to Top


🪄 Fp

Functional programming utilities including Option and Result types with JSON marshaling support.

Functions

fp Err

ExampleErr demonstrates creating an error Result.

Code
func ExampleErr() {
	// Create an error result
	result := Err[string](errors.New("something failed"))

	fmt.Printf("Is error: %t\n", result.IsErr())
	fmt.Printf("Value: %s\n", result.UnwrapOr("default"))

	// Output:
	// Is error: true
	// Value: default
}

⬆️ Back to Top


fp None

ExampleNone demonstrates creating an empty Option.

Code
func ExampleNone() {
	// Create an empty Option
	empty := None[string]()

	fmt.Printf("Has value: %t\n", empty.IsSome())
	fmt.Printf("Value: %s\n", empty.UnwrapOr("default"))

	// Output:
	// Has value: false
	// Value: default
}

⬆️ Back to Top


fp Ok

ExampleOk demonstrates creating a successful Result.

Code
func ExampleOk() {
	// Create a successful result
	result := Ok("Success!")

	fmt.Printf("Is ok: %t\n", result.IsOk())
	fmt.Printf("Value: %s\n", result.UnwrapOr("default"))

	// Output:
	// Is ok: true
	// Value: Success!
}

⬆️ Back to Top


fp OkZero

ExampleOkZero demonstrates creating a Result with zero value.

Code
func ExampleOkZero() {
	// Create a successful result with zero value
	result := OkZero[int]()

	fmt.Printf("Is ok: %t\n", result.IsOk())
	fmt.Printf("Value: %d\n", result.UnwrapOr(-1))

	// Output:
	// Is ok: true
	// Value: 0
}

⬆️ Back to Top


fp Option

ExampleOption demonstrates basic usage of the Option type.

Code
func ExampleOption() {
	// Create Some and None options
	someValue := Some(42)
	noneValue := None[int]()

	// Check if options have values
	fmt.Printf("Some has value: %v\n", someValue.IsSome())
	fmt.Printf("None has value: %v\n", noneValue.IsSome())

	// Extract values safely
	if value, ok := someValue.Unwrap(); ok {
		fmt.Printf("Value: %d\n", value)
	}

	// Output:
	// Some has value: true
	// None has value: false
	// Value: 42
}

⬆️ Back to Top


fp OptionFromPtr

ExampleOptionFromPtr demonstrates creating Option from a pointer.

Code
func ExampleOptionFromPtr() {
	// From valid pointer
	value := "hello"
	opt1 := OptionFromPtr(&value)

	// From nil pointer
	var nilPtr *string
	opt2 := OptionFromPtr(nilPtr)

	fmt.Printf("From pointer: %s\n", opt1.UnwrapOr("empty"))
	fmt.Printf("From nil: %s\n", opt2.UnwrapOr("empty"))

	// Output:
	// From pointer: hello
	// From nil: empty
}

⬆️ Back to Top


fp OptionFromTuple

ExampleOptionFromTuple demonstrates creating Option from a tuple pattern.

Code
func ExampleOptionFromTuple() {
	// Common Go pattern: value, ok
	getValue := func(key string) (string, bool) {
		data := map[string]string{"name": "Alice", "age": "25"}
		value, ok := data[key]
		return value, ok
	}

	// Convert to Option
	nameOpt := OptionFromTuple(getValue("name"))
	missingOpt := OptionFromTuple(getValue("missing"))

	fmt.Printf("Name: %s\n", nameOpt.UnwrapOr("unknown"))
	fmt.Printf("Missing: %s\n", missingOpt.UnwrapOr("unknown"))

	// Output:
	// Name: Alice
	// Missing: unknown
}

⬆️ Back to Top


fp Option_Map

ExampleOption_Map demonstrates transforming values inside Option.

Code
func ExampleOption_Map() {
	// Start with an optional number
	maybeNumber := Some(5)

	// Transform it to its square
	maybeSquare := maybeNumber.Map(func(x int) int { return x * x })

	// Transform None value
	noneNumber := None[int]()
	noneSquare := noneNumber.Map(func(x int) int { return x * x })

	fmt.Printf("Square of 5: %v\n", maybeSquare.UnwrapOr(0))
	fmt.Printf("Square of None: %v\n", noneSquare.UnwrapOr(-1))

	// Output:
	// Square of 5: 25
	// Square of None: -1
}

⬆️ Back to Top


fp Option_Match

ExampleOption_Match demonstrates pattern matching with Option.

Code
func ExampleOption_Match() {
	// Helper function that may return a value
	getValue := func(id int) Option[string] {
		if id > 0 {
			return Some(fmt.Sprintf("User_%d", id))
		}
		return None[string]()
	}

	// Pattern match on the result
	validUser := getValue(42)
	invalidUser := getValue(-1)

	result1 := validUser.Match(
		func(user string) string {
			return "Found: " + user
		},
		func() string {
			return "No user found"
		},
	)

	result2 := invalidUser.Match(
		func(user string) string {
			return "Found: " + user
		},
		func() string {
			return "No user found"
		},
	)

	fmt.Printf("Valid user: %s\n", result1)
	fmt.Printf("Invalid user: %s\n", result2)

	// Output:
	// Valid user: Found: User_42
	// Invalid user: No user found
}

⬆️ Back to Top


fp Option_Or

ExampleOption_Or demonstrates providing fallback values.

Code
func ExampleOption_Or() {
	// Create some options
	primary := None[string]()
	secondary := Some("backup")
	tertiary := Some("fallback")

	// Chain fallbacks
	result := primary.Or(secondary).Or(tertiary)

	fmt.Printf("Result: %s\n", result.UnwrapOr("default"))

	// Output:
	// Result: backup
}

⬆️ Back to Top


fp Result

ExampleResult demonstrates basic usage of the Result type.

Code
func ExampleResult() {
	// Create successful and error results
	success := Ok("Hello, World!")
	failure := Err[string](errors.New("something went wrong"))

	// Check if results are ok
	fmt.Printf("Success is ok: %v\n", success.IsOk())
	fmt.Printf("Failure is ok: %v\n", failure.IsOk())

	// Extract values safely
	if value, err := success.Unwrap(); err == nil {
		fmt.Printf("Success value: %s\n", value)
	}

	if _, err := failure.Unwrap(); err != nil {
		fmt.Printf("Failure error: %v\n", err)
	}

	// Output:
	// Success is ok: true
	// Failure is ok: false
	// Success value: Hello, World!
	// Failure error: something went wrong
}

⬆️ Back to Top


fp Result_Map

ExampleResult_Map demonstrates transforming values inside Result.

Code
func ExampleResult_Map() {
	// Start with a result containing a number
	result := Ok(5)

	// Transform to its square
	squared := result.Map(func(x int) int { return x * x })

	// Transform an error result
	errorResult := Err[int](errors.New("invalid input"))
	errorSquared := errorResult.Map(func(x int) int { return x * x })

	fmt.Printf("Square of 5: %v\n", squared.UnwrapOr(0))
	fmt.Printf("Square of error: %v\n", errorSquared.UnwrapOr(-1))

	// Output:
	// Square of 5: 25
	// Square of error: -1
}

⬆️ Back to Top


fp Result_Match

ExampleResult_Match demonstrates pattern matching with Result.

Code
func ExampleResult_Match() {
	// Helper function that may fail
	divide := func(x, y int) Result[int] {
		if y == 0 {
			return Err[int](errors.New("division by zero"))
		}
		return Ok(x / y)
	}

	// Pattern match on results
	success := divide(10, 2)
	failure := divide(10, 0)

	result1 := success.Match(
		func(value int) Result[int] {
			return Ok(value * 2)
		},
		func(err error) Result[int] {
			return Err[int](fmt.Errorf("handled: %w", err))
		},
	)

	result2 := failure.Match(
		func(value int) Result[int] {
			return Ok(value * 2)
		},
		func(err error) Result[int] {
			return Err[int](fmt.Errorf("handled: %w", err))
		},
	)

	fmt.Printf("Success result: %v\n", result1.UnwrapOr(-1))
	fmt.Printf("Failure handled: %v\n", result2.IsErr())

	// Output:
	// Success result: 10
	// Failure handled: true
}

⬆️ Back to Top


fp Result_Or

ExampleResult_Or demonstrates providing fallback results.

Code
func ExampleResult_Or() {
	// Create primary and fallback results
	primary := Err[string](errors.New("primary failed"))
	fallback := Ok("fallback value")

	// Use fallback when primary fails
	result := primary.Or(fallback)

	fmt.Printf("Result: %s\n", result.UnwrapOr("default"))

	// Output:
	// Result: fallback value
}

⬆️ Back to Top


fp Some

ExampleSome demonstrates creating an Option with a value.

Code
func ExampleSome() {
	// Create an Option containing a string
	message := Some("Hello, World!")

	fmt.Printf("Has value: %t\n", message.IsSome())
	fmt.Printf("Value: %s\n", message.UnwrapOr("default"))

	// Output:
	// Has value: true
	// Value: Hello, World!
}

⬆️ Back to Top


⬆️ Back to Top


📋 Lol

Package lol (lots of logs) provides a unified logging interface with multiple backends.

This package offers a simple, structured logging interface that can be backed by different logging implementations. Currently it supports zerolog as the primary backend.

Key features:

  • Structured logging with fields
  • Multiple log levels (trace, debug, info, warn, error, fatal, panic)
  • APM trace context integration
  • Environment-aware configuration
  • Testing utilities

Basic usage:

logger := lol.NewZerolog(
	lol.WithFields(lol.Fields{"service": "myapp"}),
	lol.WithEnv("production"),
	lol.WithLevel("info"),
	lol.WithWriter(os.Stdout),
	lol.WithAPM(lol.APMConfig{Enabled: true}),
)

logger.Info("Application started")
logger.WithField("user_id", 123).Warn("User action")

For testing:

testLogger := lol.NewTest()
testLogger.Error("This won't be printed")

Functions

lol Logger_Trace

ExampleLogger_Trace demonstrates different log levels

Code
func ExampleLogger_Trace() {
	var buf bytes.Buffer

	logger := NewZerolog(
		WithFields(Fields{"component": "auth"}),
		WithEnv(EnvDev),
		WithLevel(LevelTrace), // Set to trace level to see all messages
		WithWriter(&buf),
	)

	// Log at different levels
	logger.Trace("Entering authentication function")
	logger.Debug("Validating user credentials")
	logger.Info("User authentication successful")
	logger.Warn("Rate limit approaching")
	logger.Error("Authentication failed")

	output := buf.String()
	fmt.Printf(
		"Contains trace message: %t\n",
		bytes.Contains([]byte(output), []byte("Entering authentication")),
	)
	fmt.Printf(
		"Contains debug message: %t\n",
		bytes.Contains([]byte(output), []byte("Validating user")),
	)
	fmt.Printf(
		"Contains info message: %t\n",
		bytes.Contains([]byte(output), []byte("authentication successful")),
	)
	fmt.Printf("Contains warn message: %t\n", bytes.Contains([]byte(output), []byte("Rate limit")))
	fmt.Printf(
		"Contains error message: %t\n",
		bytes.Contains([]byte(output), []byte("Authentication failed")),
	)

	// Output:
	// Contains trace message: true
	// Contains debug message: true
	// Contains info message: true
	// Contains warn message: true
	// Contains error message: true
}

⬆️ Back to Top


lol Logger_WithField

ExampleLogger_WithField demonstrates adding contextual fields to log messages

Code
func ExampleLogger_WithField() {
	var buf bytes.Buffer

	logger := NewZerolog(
		WithFields(Fields{"app": "demo"}),
		WithEnv(EnvDev),
		WithLevel(LevelDebug),
		WithWriter(&buf),
	)

	// Chain multiple fields
	enrichedLogger := logger.WithField("request_id", "req-123").
		WithField("user_agent", "test-client")
	enrichedLogger.Info("Processing request")

	// Add more context
	enrichedLogger.WithField("duration_ms", 45).Info("Request completed")

	output := buf.String()
	fmt.Printf(
		"Output contains 'request_id': %t\n",
		bytes.Contains([]byte(output), []byte("request_id")),
	)
	fmt.Printf(
		"Output contains 'user_agent': %t\n",
		bytes.Contains([]byte(output), []byte("user_agent")),
	)
	fmt.Printf(
		"Output contains 'duration_ms': %t\n",
		bytes.Contains([]byte(output), []byte("duration_ms")),
	)

	// Output:
	// Output contains 'request_id': true
	// Output contains 'user_agent': true
	// Output contains 'duration_ms': true
}

⬆️ Back to Top


lol Logger_WithTrace

ExampleLogger_WithTrace demonstrates APM trace context integration

Code
func ExampleLogger_WithTrace() {
	var buf bytes.Buffer

	logger := NewZerolog(
		WithFields(Fields{"service": "payment-service"}),
		WithEnv(EnvDev),
		WithLevel(LevelInfo),
		WithWriter(&buf),
		WithApm(), // Enable APM tracing
	)

	// Create an APM transaction (simulating real APM integration)
	tracer := apm.DefaultTracer()
	tx := tracer.StartTransaction("payment-processing", "request")
	defer tx.End()

	// Create context with the transaction
	ctx := apm.ContextWithTransaction(context.Background(), tx)

	// Start a span for more detailed tracing
	span, ctx := apm.StartSpan(ctx, "payment-validation", "internal")
	defer span.End()

	// Create a logger with trace context
	tracedLogger := logger.WithTrace(ctx)

	// Log with trace context - these should include APM trace fields
	tracedLogger.Info("Processing payment request")
	tracedLogger.WithField("payment_id", "pay_123").
		WithField("amount", 99.99).
		Info("Payment validation started")

	// Log without trace context for comparison
	logger.Info("Regular log message without trace context")

	output := buf.String()
	fmt.Printf(
		"Output contains 'Processing payment': %t\n",
		bytes.Contains([]byte(output), []byte("Processing payment")),
	)
	fmt.Printf(
		"Output contains 'payment_id': %t\n",
		bytes.Contains([]byte(output), []byte("payment_id")),
	)
	fmt.Printf(
		"Output contains 'service': %t\n",
		bytes.Contains([]byte(output), []byte("service")),
	)

	// Check for APM trace fields in the output
	// The apmzerolog hook should add these fields when WithTrace is used
	fmt.Printf(
		"Output contains trace information: %t\n",
		bytes.Contains([]byte(output), []byte("trace")) ||
			bytes.Contains([]byte(output), []byte("transaction")) ||
			bytes.Contains([]byte(output), []byte("span")),
	)

	// Output:
	// Output contains 'Processing payment': true
	// Output contains 'payment_id': true
	// Output contains 'service': true
	// Output contains trace information: true
}

⬆️ Back to Top


lol NewZerolog

ExampleNewZerolog demonstrates creating a structured logger with zerolog backend

Code
func ExampleNewZerolog() {
	// Create a logger with custom fields and configuration
	var buf bytes.Buffer

	logger := NewZerolog(
		WithFields(Fields{"service": "example-app", "version": "1.0.0"}),
		WithEnv(EnvProd),
		WithLevel(LevelInfo),
		WithWriter(&buf),
	)

	// Log some messages
	logger.Info("Application started successfully")
	logger.WithField("user_id", 123).WithField("action", "login").Info("User logged in")
	logger.Warn("This is a warning message")

	fmt.Printf(
		"Logged output contains 'Application started': %t\n",
		bytes.Contains(buf.Bytes(), []byte("Application started")),
	)
	fmt.Printf(
		"Logged output contains 'user_id': %t\n",
		bytes.Contains(buf.Bytes(), []byte("user_id")),
	)
	fmt.Printf(
		"Logged output contains 'service': %t\n",
		bytes.Contains(buf.Bytes(), []byte("service")),
	)

	fmt.Printf(
		"Logged output contains 'version': %t\n",
		bytes.Contains(buf.Bytes(), []byte("version")),
	)

	// Output:
	// Logged output contains 'Application started': true
	// Logged output contains 'user_id': true
	// Logged output contains 'service': true
	// Logged output contains 'version': true
}

⬆️ Back to Top


⬆️ Back to Top


🗝️ Maps

Package maps provides generic utility functions to work with Go maps. It offers a functional approach to common map operations like filtering, mapping, reducing, and comparing maps.

Functions

maps Equals

ExampleEquals demonstrates comparing two maps for equality.

Code
func ExampleEquals() {
	// Create two maps
	map1 := map[string]int{"a": 1, "b": 2, "c": 3}
	map2 := map[string]int{"a": 1, "b": 2, "c": 3}
	map3 := map[string]int{"a": 1, "b": 2, "c": 4}

	// Compare using equality function
	equal1 := Equals(map1, map2, func(x, y int) bool { return x == y })
	equal2 := Equals(map1, map3, func(x, y int) bool { return x == y })

	fmt.Printf("map1 == map2: %t\n", equal1)
	fmt.Printf("map1 == map3: %t\n", equal2)
	// Output:
	// map1 == map2: true
	// map1 == map3: false
}

⬆️ Back to Top


maps Filter

ExampleFilter demonstrates filtering a map by key-value pairs.

Code
func ExampleFilter() {
	// Create a map of products to prices
	prices := map[string]int{
		"apple":  100,
		"banana": 50,
		"cherry": 200,
		"date":   75,
	}

	// Keep only items that cost more than 75
	expensive := Filter(prices, func(product string, price int) bool {
		return price > 75
	})

	fmt.Printf("Expensive items count: %d\n", len(expensive))
	// Output: Expensive items count: 2
}

⬆️ Back to Top


maps FilterMap

ExampleFilterMap demonstrates filtering and transforming in a single operation.

Code
func ExampleFilterMap() {
	// Create a map of names to ages
	ages := map[string]int{
		"Alice": 25,
		"Bob":   17,
		"Carol": 30,
		"Dave":  16,
	}

	// Keep only adults and transform to ID format
	adults := FilterMap(ages, func(name string, age int) fp.Option[tuples.Tuple2[string, string]] {
		if age >= 18 {
			id := fmt.Sprintf("ID_%s_%d", name, age)
			return fp.Some(tuples.Tuple2[string, string]{V1: name, V2: id})
		}
		return fp.None[tuples.Tuple2[string, string]]()
	})

	fmt.Printf("Adult count: %d\n", len(adults))
	// Output: Adult count: 2
}

⬆️ Back to Top


maps FilterMapTuple

ExampleFilterMapTuple demonstrates filtering and transforming using tuple returns.

Code
func ExampleFilterMapTuple() {
	// Create a map of scores
	scores := map[string]int{
		"Alice": 85,
		"Bob":   70,
		"Carol": 95,
		"Dave":  60,
	}

	// Keep high scores and convert to grade format
	grades := FilterMapTuple(scores, func(name string, score int) (string, string, bool) {
		if score >= 80 {
			var grade string
			if score >= 90 {
				grade = "A"
			} else {
				grade = "B"
			}
			return name, grade, true
		}
		return "", "", false
	})

	fmt.Printf("High performers: %d\n", len(grades))
	fmt.Printf("Alice's grade: %s\n", grades["Alice"])
	// Output:
	// High performers: 2
	// Alice's grade: B
}

⬆️ Back to Top


maps Fold

ExampleFold demonstrates folding a map with an initial value.

Code
func ExampleFold() {
	// Create a map of item prices
	prices := map[string]float64{
		"apple":  1.20,
		"banana": 0.80,
		"cherry": 2.50,
	}

	// Calculate total with initial tax
	totalWithTax := Fold(prices, func(acc float64, item string, price float64) float64 {
		return acc + price*1.1 // Add 10% tax
	}, 5.0) // Start with 5.0 base fee

	fmt.Printf("Total with tax: %.2f\n", totalWithTax)
	// Output:
	// Total with tax: 9.95
}

⬆️ Back to Top


maps Keys

ExampleKeys demonstrates extracting all keys from a map.

Code
func ExampleKeys() {
	// Create a map of products to prices
	prices := map[string]int{
		"apple":  100,
		"banana": 50,
		"cherry": 200,
	}

	// Extract all product names
	products := Keys(prices)

	fmt.Printf("Product count: %d\n", len(products))
	// Note: map iteration order is not guaranteed
	// Output:
	// Product count: 3
}

⬆️ Back to Top


maps Map

ExampleMap demonstrates transforming keys and values in a map.

Code
func ExampleMap() {
	// Create a map of numbers to their names
	numbers := map[int]string{
		1: "one",
		2: "two",
		3: "three",
	}

	// Transform to string keys and uppercase values
	transformed := Map(numbers, func(key int, value string) (string, string) {
		return fmt.Sprintf("num_%d", key), strings.ToUpper(value)
	})

	fmt.Println(transformed["num_1"])
	// Output: ONE
}

⬆️ Back to Top


maps Reduce

ExampleReduce demonstrates reducing a map to a single value.

Code
func ExampleReduce() {
	// Create a map of item quantities
	inventory := map[string]int{
		"apples":  10,
		"bananas": 5,
		"oranges": 8,
	}

	// Calculate total items (Reduce starts with zero value)
	total := Reduce(inventory, func(acc int, key string, value int) int {
		return acc + value
	})

	fmt.Printf("Total items: %d\n", total)
	// Output: Total items: 23
}

⬆️ Back to Top


maps SeqKeys

ExampleSeqKeys demonstrates iterating over map keys using iterator pattern.

Code
func ExampleSeqKeys() {
	// Create a map of products to prices
	prices := map[string]int{
		"apple":  100,
		"banana": 50,
		"cherry": 200,
	}

	// Iterate over keys lazily
	keyCount := 0
	for range SeqKeys(prices) {
		keyCount++
	}

	fmt.Printf("Key count: %d\n", keyCount)
	// Output:
	// Key count: 3
}

⬆️ Back to Top


maps SeqValues

ExampleSeqValues demonstrates iterating over map values using iterator pattern.

Code
func ExampleSeqValues() {
	// Create a map of products to prices
	prices := map[string]int{
		"apple":  100,
		"banana": 50,
		"cherry": 200,
	}

	// Calculate total using iterator
	total := 0
	for price := range SeqValues(prices) {
		total += price
	}

	fmt.Printf("Total price: %d\n", total)
	// Output:
	// Total price: 350
}

⬆️ Back to Top


maps Slice

ExampleSlice demonstrates converting a map to a slice.

Code
func ExampleSlice() {
	// Create a map of user data
	users := map[int]string{
		1: "Alice",
		2: "Bob",
		3: "Carol",
	}

	// Convert to slice of formatted strings
	userList := Slice(users, func(id int, name string) string {
		return fmt.Sprintf("ID:%d Name:%s", id, name)
	})

	fmt.Printf("Users count: %d\n", len(userList))
	// Note: map iteration order is not guaranteed
	// Output:
	// Users count: 3
}

⬆️ Back to Top


maps Values

ExampleValues demonstrates extracting all values from a map.

Code
func ExampleValues() {
	// Create a map of products to prices
	prices := map[string]int{
		"apple":  100,
		"banana": 50,
		"cherry": 200,
	}

	// Extract all prices
	allPrices := Values(prices)

	fmt.Printf("Price count: %d\n", len(allPrices))
	// Note: map iteration order is not guaranteed
	// Output:
	// Price count: 3
}

⬆️ Back to Top


⬆️ Back to Top


🔢 Num

Numeric utilities including high-precision decimal operations.

Functions

num Abs

ExampleAbs demonstrates absolute value calculation

Code
func ExampleAbs() {
	// Calculate absolute values for different types
	intVal := -42
	floatVal := -3.14

	absInt := Abs(intVal)
	absFloat := Abs(floatVal)

	fmt.Printf("Original int: %d, Absolute: %d\n", intVal, absInt)
	fmt.Printf("Original float: %.2f, Absolute: %.2f\n", floatVal, absFloat)

	// Output:
	// Original int: -42, Absolute: 42
	// Original float: -3.14, Absolute: 3.14
}

⬆️ Back to Top


num Dec_Add

ExampleDec_Add demonstrates decimal addition

Code
func ExampleDec_Add() {
	// Perform decimal addition
	price1 := MustDecFromString("123.45")
	price2 := MustDecFromString("67.89")

	total := price1.Add(price2)

	fmt.Printf("Price 1: %s\n", price1.String())
	fmt.Printf("Price 2: %s\n", price2.String())
	fmt.Printf("Total: %s\n", total.String())

	// Output:
	// Price 1: 123.45
	// Price 2: 67.89
	// Total: 191.34
}

⬆️ Back to Top


num Dec_Div

ExampleDec_Div demonstrates decimal division

Code
func ExampleDec_Div() {
	// Calculate unit price
	totalCost := MustDecFromString("127.50")
	quantity := MustDecFromString("25")

	unitPrice := totalCost.Div(quantity)

	fmt.Printf("Total cost: %s\n", totalCost.String())
	fmt.Printf("Quantity: %s\n", quantity.String())
	fmt.Printf("Unit price: %s\n", unitPrice.String())

	// Output:
	// Total cost: 127.5
	// Quantity: 25
	// Unit price: 5.1
}

⬆️ Back to Top


num Dec_IsZero

ExampleDec_IsZero demonstrates zero checking

Code
func ExampleDec_IsZero() {
	// Check if decimal is zero
	zero := Zero
	nonZero := MustDecFromString("0.01")
	alsoZero := MustDecFromString("0.00")

	fmt.Printf("Zero value: %s, IsZero: %t\n", zero.String(), zero.IsZero())
	fmt.Printf("Non-zero value: %s, IsZero: %t\n", nonZero.String(), nonZero.IsZero())
	fmt.Printf("Also zero: %s, IsZero: %t\n", alsoZero.String(), alsoZero.IsZero())

	// Output:
	// Zero value: 0, IsZero: true
	// Non-zero value: 0.01, IsZero: false
	// Also zero: 0, IsZero: true
}

⬆️ Back to Top


num Dec_LessThan

ExampleDec_LessThan demonstrates decimal comparison

Code
func ExampleDec_LessThan() {
	// Compare decimal values
	price1 := MustDecFromString("99.99")
	price2 := MustDecFromString("100.00")
	price3 := MustDecFromString("99.99")

	fmt.Printf("Price 1: %s\n", price1.String())
	fmt.Printf("Price 2: %s\n", price2.String())
	fmt.Printf("Price 3: %s\n", price3.String())

	fmt.Printf("Price 1 < Price 2: %t\n", price1.LessThan(price2))
	fmt.Printf("Price 1 > Price 2: %t\n", price1.GreaterThan(price2))
	fmt.Printf("Price 1 == Price 3: %t\n", price1.Equal(price3))
	fmt.Printf("Price 1 <= Price 2: %t\n", price1.LessThanOrEqual(price2))

	// Output:
	// Price 1: 99.99
	// Price 2: 100
	// Price 3: 99.99
	// Price 1 < Price 2: true
	// Price 1 > Price 2: false
	// Price 1 == Price 3: true
	// Price 1 <= Price 2: true
}

⬆️ Back to Top


num Dec_Mul

ExampleDec_Mul demonstrates decimal multiplication

Code
func ExampleDec_Mul() {
	// Calculate area
	length := MustDecFromString("12.5")
	width := MustDecFromString("8.4")

	area := length.Mul(width)

	fmt.Printf("Length: %s\n", length.String())
	fmt.Printf("Width: %s\n", width.String())
	fmt.Printf("Area: %s\n", area.String())

	// Output:
	// Length: 12.5
	// Width: 8.4
	// Area: 105
}

⬆️ Back to Top


num Dec_Percent

ExampleDec_Percent demonstrates percentage calculations

Code
func ExampleDec_Percent() {
	// Calculate percentage
	value := MustDecFromString("850.00")
	percentage := MustDecFromString("15") // 15%

	percentValue := value.ApplyPercent(percentage)
	finalValue := value.AddPercent(percentage)

	fmt.Printf("Original value: %s\n", value.String())
	fmt.Printf("Percentage: %s%%\n", percentage.String())
	fmt.Printf("Percentage amount: %s\n", percentValue.String())
	fmt.Printf("Final value (with percentage): %s\n", finalValue.String())

	// Output:
	// Original value: 850
	// Percentage: 15%
	// Percentage amount: 127.5
	// Final value (with percentage): 977.5
}

⬆️ Back to Top


num Dec_Round

ExampleDec_Round demonstrates decimal rounding

Code
func ExampleDec_Round() {
	// Round to different precision levels
	value := MustDecFromString("123.456789")

	rounded2 := value.RoundTo(2)
	rounded4 := value.RoundTo(4)
	rounded0 := value.RoundTo(0)

	fmt.Printf("Original: %s\n", value.String())
	fmt.Printf("Rounded to 2 decimals: %s\n", rounded2.String())
	fmt.Printf("Rounded to 4 decimals: %s\n", rounded4.String())
	fmt.Printf("Rounded to 0 decimals: %s\n", rounded0.String())

	// Output:
	// Original: 123.456789
	// Rounded to 2 decimals: 123.46
	// Rounded to 4 decimals: 123.4568
	// Rounded to 0 decimals: 123
}

⬆️ Back to Top


num Dec_Sub

ExampleDec_Sub demonstrates decimal subtraction

Code
func ExampleDec_Sub() {
	// Perform decimal subtraction
	balance := MustDecFromString("1000.00")
	withdrawal := MustDecFromString("750.25")

	remaining := balance.Sub(withdrawal)

	fmt.Printf("Initial balance: %s\n", balance.String())
	fmt.Printf("Withdrawal: %s\n", withdrawal.String())
	fmt.Printf("Remaining: %s\n", remaining.String())

	// Output:
	// Initial balance: 1000
	// Withdrawal: 750.25
	// Remaining: 249.75
}

⬆️ Back to Top


num MustDecFromAny

ExampleMustDecFromAny demonstrates creating a decimal from any supported type

Code
func ExampleMustDecFromAny() {
	// Create decimals from different types
	fromInt := MustDecFromAny(100)
	fromFloat := MustDecFromAny(3.14159)
	fromString := MustDecFromAny("42.42")

	fmt.Printf("From int: %s\n", fromInt.String())
	fmt.Printf("From float: %s\n", fromFloat.String())
	fmt.Printf("From string: %s\n", fromString.String())

	// Output:
	// From int: 100
	// From float: 3.14159
	// From string: 42.42
}

⬆️ Back to Top


num MustDecFromString

ExampleMustDecFromString demonstrates creating a decimal from a string (panics on error)

Code
func ExampleMustDecFromString() {
	// Create decimal from valid string
	price := MustDecFromString("999.99")

	fmt.Printf("Price: %s\n", price.String())
	if f, ok := price.Float64(); ok {
		fmt.Printf("As float: %.2f\n", f)
	}

	// Output:
	// Price: 999.99
}

⬆️ Back to Top


num NewDecFromFloat

ExampleNewDecFromFloat demonstrates creating a decimal from a float

Code
func ExampleNewDecFromFloat() {
	// Create decimal from float
	temperature := NewDecFromFloat(36.5)

	fmt.Printf("Temperature: %s\n", temperature.String())
	if f, ok := temperature.Float64(); ok {
		fmt.Printf("As float: %.1f\n", f)
	}
	fmt.Printf("Number of decimals: %d\n", temperature.NumberOfDecimals())

	// Output:
	// Temperature: 36.5
	// As float: 36.5
	// Number of decimals: 1
}

⬆️ Back to Top


num NewDecFromInt

ExampleNewDecFromInt demonstrates creating a decimal from an integer

Code
func ExampleNewDecFromInt() {
	// Create decimal from integer
	quantity := NewDecFromInt(42)

	fmt.Printf("Quantity: %s\n", quantity.String())
	fmt.Printf("As int: %d\n", quantity.IntPart())
	fmt.Printf("Is zero: %t\n", quantity.IsZero())

	// Output:
	// Quantity: 42
	// As int: 42
	// Is zero: false
}

⬆️ Back to Top


num NewDecFromString

ExampleNewDecFromString demonstrates creating a decimal from a string

Code
func ExampleNewDecFromString() {
	// Create decimal from string
	price, err := NewDecFromString("123.456")
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	fmt.Printf("Price: %s\n", price.String())
	fmt.Printf("Is set: %t\n", price.Isset())

	// Try with invalid string
	_, err = NewDecFromString("invalid")
	fmt.Printf("Invalid string error: %v\n", err != nil)

	// Output:
	// Price: 123.456
	// Is set: true
	// Invalid string error: true
}

⬆️ Back to Top


⬆️ Back to Top


👉 Ptr

Package ptr provides pointer utility functions for Go.

Functions

ptr Ptr

ExamplePtr demonstrates creating a pointer to a value.

Code
func ExamplePtr() {
	// Get pointer to a literal
	name := Ptr("Alice")
	age := Ptr(30)

	fmt.Println(*name, *age)
	// Output:
	// Alice 30
}

⬆️ Back to Top


ptr Ptr_struct

ExamplePtr_struct demonstrates creating a pointer to a struct.

Code
func ExamplePtr_struct() {
	type Config struct {
		Host string
		Port int
	}

	// Get pointer to struct literal
	config := Ptr(Config{
		Host: "localhost",
		Port: 8080,
	})

	fmt.Println(config.Host, config.Port)
	// Output:
	// localhost 8080
}

⬆️ Back to Top


⬆️ Back to Top


⛓️ Slices

Package slices provides a comprehensive set of generic utility functions for working with slices. It offers a functional approach to common slice operations such as transforming, filtering, searching, and manipulating elements in a type-safe manner.

Functions

slices All

ExampleAll demonstrates checking if all elements satisfy a condition.

Code
func ExampleAll() {
	// Create a slice of positive numbers
	numbers := []int{1, 2, 3, 4, 5}

	// Check if all numbers are positive
	allPositive := All(numbers, func(n int) bool {
		return n > 0
	})

	// Check if all numbers are even
	allEven := All(numbers, func(n int) bool {
		return n%2 == 0
	})

	fmt.Printf("All positive: %t\n", allPositive)
	fmt.Printf("All even: %t\n", allEven)
	// Output:
	// All positive: true
	// All even: false
}

⬆️ Back to Top


slices Contains

ExampleContains demonstrates checking if any element satisfies a condition.

Code
func ExampleContains() {
	// Create a slice of numbers
	numbers := []int{1, 2, 3, 4, 5}

	// Check if any number is greater than 3
	hasLarge := Contains(numbers, func(n int) bool {
		return n > 3
	})

	// Check if any number is negative
	hasNegative := Contains(numbers, func(n int) bool {
		return n < 0
	})

	fmt.Printf("Has number > 3: %t\n", hasLarge)
	fmt.Printf("Has negative: %t\n", hasNegative)
	// Output:
	// Has number > 3: true
	// Has negative: false
}

⬆️ Back to Top


slices Filter

ExampleFilter demonstrates filtering a slice to keep only elements that satisfy a condition.

Code
func ExampleFilter() {
	// Create a slice of numbers
	numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	// Filter to keep only even numbers
	evenNumbers := Filter(numbers, func(n int) bool {
		return n%2 == 0
	})

	fmt.Println(evenNumbers)
	// Output: [2 4 6 8 10]
}

⬆️ Back to Top


slices FilterMap

ExampleFilterMap demonstrates filtering and transforming in a single operation.

Code
func ExampleFilterMap() {
	// Create a slice of numbers
	numbers := []int{1, 2, 3, 4, 5, 6}

	// Keep only even numbers and square them
	evenSquares := FilterMap(numbers, func(n int) fp.Option[int] {
		if n%2 == 0 {
			return fp.Some(n * n)
		}
		return fp.None[int]()
	})

	fmt.Println(evenSquares)
	// Output: [4 16 36]
}

⬆️ Back to Top


slices Find

ExampleFind demonstrates finding the first element that matches a condition.

Code
func ExampleFind() {
	// Create a slice of names
	names := []string{"Alice", "Bob", "Charlie", "David"}

	// Find the first name that starts with 'C'
	result, found := Find(names, func(name string) bool {
		return len(name) > 0 && name[0] == 'C'
	})

	fmt.Printf("Found: %t, Name: %s\n", found, result)
	// Output: Found: true, Name: Charlie
}

⬆️ Back to Top


slices Fold

ExampleFold demonstrates folding a slice with an initial value.

Code
func ExampleFold() {
	// Create a slice of strings
	words := []string{"Hello", "World", "from", "Go"}

	// Join with custom separator and prefix
	result := Fold(words, func(acc, word string) string {
		if acc == "" {
			return "Greeting: " + word
		}
		return acc + " " + word
	}, "")

	fmt.Printf("Result: %s\n", result)
	// Output:
	// Result: Greeting: Hello World from Go
}

⬆️ Back to Top


slices Map

ExampleMap demonstrates transforming elements in a slice.

Code
func ExampleMap() {
	// Create a slice of numbers
	numbers := []int{1, 2, 3, 4, 5}

	// Transform each number by squaring it
	squares := Map(numbers, func(n int) int {
		return n * n
	})

	fmt.Println(squares)
	// Output: [1 4 9 16 25]
}

⬆️ Back to Top


slices Reduce

ExampleReduce demonstrates combining all elements into a single value.

Code
func ExampleReduce() {
	// Create a slice of numbers
	numbers := []int{1, 2, 3, 4, 5}

	// Sum all numbers
	sum := Reduce[int, int](numbers, func(acc, curr int) int {
		return acc + curr
	})

	fmt.Println(sum)
	// Output: 15
}

⬆️ Back to Top


slices Some

ExampleSome demonstrates checking if some elements satisfy a condition.

Code
func ExampleSome() {
	// Create a slice of words
	words := []string{"hello", "world", "go", "programming"}

	// Check if some words are short (< 4 characters)
	hasShort := Some(words, func(word string) bool {
		return len(word) < 4
	})

	fmt.Printf("Has short words: %t\n", hasShort)
	// Output:
	// Has short words: true
}

⬆️ Back to Top


slices ToMap

ExampleToMap demonstrates converting a slice to a map using a key function.

Code
func ExampleToMap() {
	// Create a slice of words
	words := []string{"apple", "banana", "cherry"}

	// Convert to map with first letter as key
	wordMap := ToMap(words, func(word string) rune {
		return rune(word[0])
	})

	fmt.Printf("'a' word: %s\n", wordMap['a'])
	fmt.Printf("'b' word: %s\n", wordMap['b'])
	// Output:
	// 'a' word: apple
	// 'b' word: banana
}

⬆️ Back to Top


slices Uniq

ExampleUniq demonstrates removing duplicate elements from a slice.

Code
func ExampleUniq() {
	// Create a slice with duplicate elements
	numbers := []int{1, 2, 2, 3, 3, 3, 4, 5, 5}

	// Remove duplicates
	unique := Uniq(numbers)

	fmt.Printf("Original: %v\n", numbers)
	fmt.Printf("Unique:   %v\n", unique)
	// Output:
	// Original: [1 2 2 3 3 3 4 5 5]
	// Unique:   [1 2 3 4 5]
}

⬆️ Back to Top


slices UniqFn

ExampleUniqFn demonstrates removing duplicates using a custom equality function.

Code
func ExampleUniqFn() {
	type person struct {
		name string
		age  int
	}

	// Create a slice with people having duplicate names
	people := []person{
		{"Alice", 25},
		{"Bob", 30},
		{"Alice", 40}, // duplicate name
		{"Carol", 35},
		{"Bob", 50}, // duplicate name
	}

	// Remove duplicates by name
	uniqueByName := UniqFn(people, func(a, b person) bool {
		return a.name == b.name
	})

	fmt.Printf("Original count: %d\n", len(people))
	fmt.Printf("Unique by name count: %d\n", len(uniqueByName))
	for _, p := range uniqueByName {
		fmt.Printf("  %s (%d)\n", p.name, p.age)
	}
	// Output:
	// Original count: 5
	// Unique by name count: 3
	//   Alice (25)
	//   Bob (30)
	//   Carol (35)
}

⬆️ Back to Top


slices UniqSorted

ExampleUniqSorted demonstrates removing consecutive duplicate elements from a sorted slice.

Code
func ExampleUniqSorted() {
	// Create a sorted slice with consecutive duplicate elements
	sortedNumbers := []int{1, 2, 2, 3, 3, 3, 4, 5, 5}

	// Remove consecutive duplicates
	unique := UniqSorted(sortedNumbers)

	fmt.Printf("Original sorted: %v\n", sortedNumbers)
	fmt.Printf("Unique:          %v\n", unique)
	// Output:
	// Original sorted: [1 2 2 3 3 3 4 5 5]
	// Unique:          [1 2 3 4 5]
}

⬆️ Back to Top


slices UniqSortedFn

ExampleUniqSortedFn demonstrates removing consecutive duplicates using a custom equality function.

Code
func ExampleUniqSortedFn() {
	type person struct {
		name string
		age  int
	}

	// Create a slice sorted by name with consecutive duplicates
	sortedPeople := []person{
		{"Alice", 25},
		{"Alice", 40}, // consecutive duplicate name
		{"Bob", 30},
		{"Bob", 50}, // consecutive duplicate name
		{"Carol", 35},
	}

	// Remove consecutive duplicates by name
	uniqueByName := UniqSortedFn(sortedPeople, func(a, b person) bool {
		return a.name == b.name
	})

	fmt.Printf("Original count: %d\n", len(sortedPeople))
	fmt.Printf("Unique by name count: %d\n", len(uniqueByName))
	for _, p := range uniqueByName {
		fmt.Printf("  %s (%d)\n", p.name, p.age)
	}
	// Output:
	// Original count: 5
	// Unique by name count: 3
	//   Alice (25)
	//   Bob (30)
	//   Carol (35)
}

⬆️ Back to Top


⬆️ Back to Top


🌊 Streams

Package streams provides interfaces and types for reading and writing streams of data.

Functions

streams Batch

ExampleBatch demonstrates grouping stream elements into batches.

Code
func ExampleBatch() {
	// Create a stream from a slice of integers
	data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	stream := MemReader(data, nil)

	// Group into batches of 3
	batchStream := Batch(stream, 3)

	// Collect the results
	result, _ := Consume(batchStream)
	for i, batch := range result {
		fmt.Printf("Batch %d: %v\n", i+1, batch)
	}
	// Output:
	// Batch 1: [1 2 3]
	// Batch 2: [4 5 6]
	// Batch 3: [7 8 9]
	// Batch 4: [10]
}

⬆️ Back to Top


streams CSV

ExampleCSV demonstrates reading CSV data from a string.

Code
func ExampleCSV() {
	// Create a CSV reader from a string
	csvData := "name,age,city\nAlice,25,NYC\nBob,30,LA\nCharlie,35,Chicago"
	reader := io.NopCloser(strings.NewReader(csvData))

	// Create a CSV stream directly
	csvStream, _ := CSV[[]string](
		WithCSVReader(reader),
		WithCSVSeparator(","),
	)

	// Collect the results
	result, _ := Consume(csvStream)
	for i, row := range result {
		fmt.Printf("Row %d: %v\n", i+1, row)
	}
	// Output:
	// Row 1: [name age city]
	// Row 2: [Alice 25 NYC]
	// Row 3: [Bob 30 LA]
	// Row 4: [Charlie 35 Chicago]
}

⬆️ Back to Top


streams CSVTransform

ExampleCSVTransform demonstrates converting a stream to CSV format.

Code
func ExampleCSVTransform() {
	// Create a stream of employees
	employees := []Employee{
		{ID: 1, Name: "Alice Johnson", Department: "Engineering", Salary: 75000.00},
		{ID: 2, Name: "Bob Smith", Department: "Marketing", Salary: 65000.00},
		{ID: 3, Name: "Charlie Brown", Department: "Engineering", Salary: 80000.00},
	}
	stream := MemReader(employees, nil)

	// Transform to CSV with comma separator
	transform := CSVTransform(stream, CSVSeparatorComma)
	transform.WriteTo(os.Stdout)

	// Output:
	// ID,Name,Department,Salary
	// 1,Alice Johnson,Engineering,75000.00
	// 2,Bob Smith,Marketing,65000.00
	// 3,Charlie Brown,Engineering,80000.00
}

⬆️ Back to Top


streams CSVTransform_tabSeparated

ExampleCSVTransform_tabSeparated demonstrates CSV with tab separator.

Code
func ExampleCSVTransform_tabSeparated() {

	// Create a stream of products
	products := []ProductCSV{
		{SKU: "LAPTOP-001", Name: "Gaming Laptop", Price: 1299.99},
		{SKU: "MOUSE-002", Name: "Wireless Mouse", Price: 49.99},
		{SKU: "KEYBOARD-003", Name: "Mechanical Keyboard", Price: 129.99},
	}
	stream := MemReader(products, nil)

	// Transform to CSV with tab separator
	transform := CSVTransform(stream, CSVSeparatorTab)
	transform.WriteTo(os.Stdout)

	// Output:
	// SKU	Product Name	Price
	// LAPTOP-001	Gaming Laptop	$1299.99
	// MOUSE-002	Wireless Mouse	$49.99
	// KEYBOARD-003	Mechanical Keyboard	$129.99
}

⬆️ Back to Top


streams ConsumeErrSkip

ExampleConsumeErrSkip demonstrates consuming a stream while skipping errors.

Code
func ExampleConsumeErrSkip() {
	// Create a filter stream that may produce errors
	reader := strings.NewReader("1\n2\ninvalid\n4\n5")
	numbersStream := Lines(reader)

	// Create a filter that converts strings to numbers (may fail)
	filterStream := FilterMap(numbersStream, func(s string) (int, bool) {
		// Simulate conversion that might fail
		if s == "invalid" {
			return 0, false // This will be skipped
		}
		// Simple conversion for demonstration
		switch s {
		case "1":
			return 1, true
		case "2":
			return 2, true
		case "4":
			return 4, true
		case "5":
			return 5, true
		default:
			return 0, false
		}
	})

	// Consume all valid numbers, skipping errors
	numbers := ConsumeErrSkip(filterStream)

	fmt.Printf("Valid numbers: %v\n", numbers)

	// Output:
	// Valid numbers: [1 2 4 5]
}

⬆️ Back to Top


streams DB

ExampleDB demonstrates how to use DB with database rows.

Code
func ExampleDB() {
	// Mock data that simulates database rows
	mockData := &mockRows{
		data: [][]any{
			{1, "Alice"},
			{2, "Bob"},
			{3, "Charlie"},
		},
	}

	// Create a stream with a scan function
	stream := DB(mockData, func(rows DBRows, user *User) error {
		return rows.Scan(&user.ID, &user.Name)
	})

	// Iterate through the stream
	for stream.Next() {
		user := stream.Data()
		fmt.Printf("User ID: %d, Name: %s\n", user.ID, user.Name)
	}

	// Check for errors
	if err := stream.Err(); err != nil {
		log.Printf("Error during streaming: %v", err)
	}

	// Output:
	// User ID: 1, Name: Alice
	// User ID: 2, Name: Bob
	// User ID: 3, Name: Charlie
}

⬆️ Back to Top


streams Filter

ExampleFilter demonstrates filtering a stream of integers to keep only even numbers.

Code
func ExampleFilter() {
	// Create a stream from a slice of integers
	data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	stream := MemReader(data, nil)

	// Filter to keep only even numbers
	evenStream := Filter(stream, func(n int) bool {
		return n%2 == 0
	})

	// Collect the results
	result, _ := Consume(evenStream)
	fmt.Println(result)
	// Output: [2 4 6 8 10]
}

⬆️ Back to Top


streams FilterMap

ExampleFilterMap demonstrates filtering and transforming in a single operation.

Code
func ExampleFilterMap() {
	// Create a stream from a slice of integers
	data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	stream := MemReader(data, nil)

	// Filter even numbers and convert them to strings
	evenStrings := FilterMap(stream, func(n int) (string, bool) {
		if n%2 == 0 {
			return strconv.Itoa(n), true
		}
		return "", false
	})

	// Collect the results
	result, _ := Consume(evenStrings)
	fmt.Println(result)
	// Output: [2 4 6 8 10]
}

⬆️ Back to Top


streams Flatten

ExampleFlatten demonstrates flattening a stream of slices.

Code
func ExampleFlatten() {
	// Create a stream from a slice of slices
	data := [][]int{{1, 2}, {3, 4, 5}, {6}, {7, 8, 9}}
	stream := MemReader(data, nil)

	// Flatten the slices
	flattened := Flatten(stream)

	// Collect the results
	result, _ := Consume(flattened)
	fmt.Println(result)
	// Output: [1 2 3 4 5 6 7 8 9]
}

⬆️ Back to Top


streams Group

ExampleGroup demonstrates grouping consecutive items with the same key.

Code
func ExampleGroup() {
	// Create a stream from a slice of strings
	data := []string{"apple", "apricot", "banana", "blueberry", "cherry", "coconut"}
	stream := MemReader(data, nil)

	// Group by first letter
	Grouped := Group(stream, func(s string) rune {
		return rune(s[0])
	})

	// Collect the results
	result, _ := Consume(Grouped)
	for _, group := range result {
		fmt.Printf("Group: %v\n", group)
	}
	// Output:
	// Group: [apple apricot]
	// Group: [banana blueberry]
	// Group: [cherry coconut]
}

⬆️ Back to Top


streams JSON

ExampleJSON demonstrates reading JSON data line by line.

Code
func ExampleJSON() {
		// Create JSON-lines data (each line is a separate JSON object)
		jsonData := `{"name":"Alice","age":25}
	{"name":"Bob","age":30}
	{"name":"Charlie","age":35}`

		reader := strings.NewReader(jsonData)

		// Create a JSON stream for a simple struct
		type Person struct {
			Name string `json:"name"`
			Age  int    `json:"age"`
		}

		jsonStream := JSON[Person](io.NopCloser(reader))

		// Collect the results
		result, _ := Consume(jsonStream)
		for _, person := range result {
			fmt.Printf("Person: %s, Age: %d\n", person.Name, person.Age)
		}
		// Output:
		// Person: Alice, Age: 25
		// Person: Bob, Age: 30
		// Person: Charlie, Age: 35
}

⬆️ Back to Top


streams JSONEachRowTransform

ExampleJSONEachRowTransform demonstrates converting a stream to JSON lines format.

Code
func ExampleJSONEachRowTransform() {
	// Define a simple structure for demonstration
	type LogEntry struct {
		Timestamp string `json:"timestamp"`
		Level     string `json:"level"`
		Message   string `json:"message"`
	}

	// Create a stream of log entries
	logs := []LogEntry{
		{Timestamp: "2025-06-28T10:00:00Z", Level: "INFO", Message: "Application started"},
		{Timestamp: "2025-06-28T10:01:00Z", Level: "WARN", Message: "High memory usage detected"},
		{Timestamp: "2025-06-28T10:02:00Z", Level: "ERROR", Message: "Database connection failed"},
	}
	stream := MemReader(logs, nil)

	// Transform to JSON lines format and write to stdout
	transform := JSONEachRowTransform(stream)
	transform.WriteTo(os.Stdout)

	// Output:
	// {"timestamp":"2025-06-28T10:00:00Z","level":"INFO","message":"Application started"}
	// {"timestamp":"2025-06-28T10:01:00Z","level":"WARN","message":"High memory usage detected"}
	// {"timestamp":"2025-06-28T10:02:00Z","level":"ERROR","message":"Database connection failed"}
}

⬆️ Back to Top


streams JSONTransform

ExampleJSONTransform demonstrates converting a stream to JSON array format.

Code
func ExampleJSONTransform() {
	// Define a simple structure for demonstration
	type Person struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	}

	// Create a stream from a slice of persons
	people := []Person{
		{ID: 1, Name: "Alice"},
		{ID: 2, Name: "Bob"},
		{ID: 3, Name: "Charlie"},
	}
	stream := MemReader(people, nil)

	// Transform to JSON and write to stdout
	transform := JSONTransform(stream)
	transform.WriteTo(os.Stdout)

	// Output:
	// [{"id":1,"name":"Alice"},{"id":2,"name":"Bob"},{"id":3,"name":"Charlie"}]
}

⬆️ Back to Top


streams Lines

ExampleLines demonstrates reading lines from a string.

Code
func ExampleLines() {
	// Create a reader from a multiline string
	text := "line1\nline2\nline3\n"
	reader := strings.NewReader(text)

	// Create a lines stream
	lineStream := Lines(reader)

	// Collect the results
	result, _ := Consume(lineStream)
	fmt.Println(result)
	// Output: [line1 line2 line3]
}

⬆️ Back to Top


streams Map

ExampleMap demonstrates transforming elements in a stream.

Code
func ExampleMap() {
	// Create a stream from a slice of integers
	data := []int{1, 2, 3, 4, 5}
	stream := MemReader(data, nil)

	// Transform integers to their string representation
	stringStream := Map(stream, func(n int) string {
		return fmt.Sprintf("number_%d", n)
	})

	// Collect the results
	result, _ := Consume(stringStream)
	fmt.Println(result)
	// Output: [number_1 number_2 number_3 number_4 number_5]
}

⬆️ Back to Top


streams MemWriter

ExampleMemWriter demonstrates writing items to memory.

Code
func ExampleMemWriter() {
	// Create a memory writer for strings
	writer := MemWriter[string]()

	// Write some items
	items := []string{"hello", "world", "from", "memory"}
	for _, item := range items {
		writer.Write(item)
	}

	// Get all items
	result := writer.Items()

	fmt.Printf("Items written: %d\n", len(result))
	fmt.Printf("Items: %v\n", result)
	// Output:
	// Items written: 4
	// Items: [hello world from memory]
}

⬆️ Back to Top


streams Multicast

ExampleMulticast demonstrates broadcasting a stream to multiple destinations.

Code
func ExampleMulticast() {
	// Create a stream of numbers
	reader := strings.NewReader("1\n2\n3\n4\n5")
	source := Lines(reader)

	// Create two memory writers to collect data separately
	dest1 := MemWriter[string]()
	dest2 := MemWriter[string]()

	// Multicast the stream to both destinations
	counts, err := Multicast(source, dest1, dest2)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	fmt.Printf("Written to dest1: %d items\n", counts[0])
	fmt.Printf("Written to dest2: %d items\n", counts[1])
	fmt.Printf("Dest1 data: %v\n", dest1.Items())
	fmt.Printf("Dest2 data: %v\n", dest2.Items())

	// Output:
	// Written to dest1: 5 items
	// Written to dest2: 5 items
	// Dest1 data: [1 2 3 4 5]
	// Dest2 data: [1 2 3 4 5]
}

⬆️ Back to Top


streams Pipe

ExamplePipe demonstrates piping data from one stream to another.

Code
func ExamplePipe() {
	// Create a source stream
	data := []string{"hello", "world", "from", "streams"}
	source := MemReader(data, nil)

	// Create a destination
	dest := MemWriter[string]()

	// Pipe data from source to destination
	bytesWritten, _ := Pipe(source, dest)

	fmt.Printf("Items written: %d\n", bytesWritten)
	fmt.Printf("Items: %v\n", dest.Items())
	// Output:
	// Items written: 4
	// Items: [hello world from streams]
}

⬆️ Back to Top


streams PipeCSV

ExamplePipeCSV demonstrates using the PipeCSV convenience function.

Code
func ExamplePipeCSV() {
	// Create a stream of employees
	employees := []Employee{
		{ID: 101, Name: "Diana Prince", Department: "Legal", Salary: 90000.00},
		{ID: 102, Name: "Clark Kent", Department: "Journalism", Salary: 55000.00},
	}
	stream := MemReader(employees, nil)

	// Use PipeCSV to write directly to stdout with comma separator
	rowsWritten, err := PipeCSV(stream, os.Stdout, CSVSeparatorComma)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	fmt.Printf("Rows written: %d\n", rowsWritten)

	// Output:
	// ID,Name,Department,Salary
	// 101,Diana Prince,Legal,90000.00
	// 102,Clark Kent,Journalism,55000.00
	// Rows written: 3
}

⬆️ Back to Top


streams PipeJSON

ExamplePipeJSON demonstrates using the PipeJSON convenience function.

Code
func ExamplePipeJSON() {
	// Define a simple structure
	type Product struct {
		ID    int     `json:"id"`
		Name  string  `json:"name"`
		Price float64 `json:"price"`
	}

	// Create a stream of products
	products := []Product{
		{ID: 1, Name: "Laptop", Price: 999.99},
		{ID: 2, Name: "Mouse", Price: 29.99},
	}
	stream := MemReader(products, nil)

	// Use PipeJSON to write directly to stdout
	bytesWritten, err := PipeJSON(stream, os.Stdout)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	fmt.Printf("\nBytes written: %d\n", bytesWritten)

	// Output:
	// [{"id":1,"name":"Laptop","price":999.99},{"id":2,"name":"Mouse","price":29.99}]
	// Bytes written: 79
}

⬆️ Back to Top


streams PipeJSONEachRow

ExamplePipeJSONEachRow demonstrates using the PipeJSONEachRow convenience function.

Code
func ExamplePipeJSONEachRow() {
	// Define a simple metric structure
	type Metric struct {
		Name  string  `json:"name"`
		Value float64 `json:"value"`
		Unit  string  `json:"unit"`
	}

	// Create a stream of metrics
	metrics := []Metric{
		{Name: "cpu_usage", Value: 85.5, Unit: "percent"},
		{Name: "memory_usage", Value: 1024, Unit: "MB"},
		{Name: "disk_usage", Value: 75.2, Unit: "percent"},
	}
	stream := MemReader(metrics, nil)

	// Use PipeJSONEachRow to write to stdout
	bytesWritten, err := PipeJSONEachRow(stream, os.Stdout)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}
	fmt.Printf("Bytes written: %d\n", bytesWritten)

	// Output:
	// {"name":"cpu_usage","value":85.5,"unit":"percent"}
	// {"name":"memory_usage","value":1024,"unit":"MB"}
	// {"name":"disk_usage","value":75.2,"unit":"percent"}
	// Bytes written: 152
}

⬆️ Back to Top


streams Reader

ExampleReader demonstrates reading byte chunks from an io.Reader.

Code
func ExampleReader() {
	// Create data to read
	data := "line1\nline2\nline3\n"
	reader := strings.NewReader(data)

	// Create a byte stream
	stream := Reader(reader)

	// Read all chunks
	var chunks []string
	for stream.Next() {
		chunks = append(chunks, string(stream.Data()))
	}

	fmt.Printf("Chunks: %d\n", len(chunks))
	fmt.Printf("First chunk: %q\n", chunks[0])
	// Output:
	// Chunks: 3
	// First chunk: "line1\n"
}

⬆️ Back to Top


streams Reduce

ExampleReduce demonstrates using Reduce to sum numbers from a stream.

Code
func ExampleReduce() {
	// Create a stream of numbers from strings
	reader := strings.NewReader("10\n20\n30\n40\n50")
	lines := Lines(reader)

	// Convert strings to numbers and sum them
	sum, _ := Reduce(Map(lines, func(s string) int {
		n, _ := strconv.Atoi(s)
		return n
	}), func(acc, n int) int {
		return acc + n
	}, 0)

	fmt.Printf("Sum: %d\n", sum)

	// Output:
	// Sum: 150
}

⬆️ Back to Top


streams ReduceMap

ExampleReduceMap demonstrates reducing a stream to a map with aggregated values.

Code
func ExampleReduceMap() {
	// Create a stream of words
	reader := strings.NewReader("apple\nbanana\napple\ncherry\nbanana\napple")
	stream := Lines(reader)

	// Count occurrences of each word
	counts, _ := ReduceMap(stream, func(acc map[string]int, word string) map[string]int {
		acc[word]++
		return acc
	})

	fmt.Printf("apple: %d\n", counts["apple"])
	fmt.Printf("banana: %d\n", counts["banana"])
	fmt.Printf("cherry: %d\n", counts["cherry"])

	// Output:
	// apple: 3
	// banana: 2
	// cherry: 1
}

⬆️ Back to Top


streams ReduceSlice

ExampleReduceSlice demonstrates collecting filtered items from a stream.

Code
func ExampleReduceSlice() {
	// Create a stream of words
	reader := strings.NewReader("cat\ndog\nelephant\nant\nbutterfly\nbird")
	stream := Lines(reader)

	// Collect only words longer than 3 characters
	longWords, _ := ReduceSlice(stream, func(acc []string, word string) []string {
		if len(word) > 3 {
			return append(acc, word)
		}
		return acc
	})

	fmt.Printf("Long words: %v\n", longWords)

	// Output:
	// Long words: [elephant butterfly bird]
}

⬆️ Back to Top


streams WriteAll

ExampleWriteAll demonstrates writing a slice to a stream.

Code
func ExampleWriteAll() {
	// Create data to write
	data := []string{"hello", "world", "streams"}

	// Create a memory writer
	writer := MemWriter[string]()

	// Write all data
	bytesWritten, err := WriteAll(writer, data)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	fmt.Printf("Bytes written: %d\n", bytesWritten)
	fmt.Printf("Items: %v\n", writer.Items())
	// Output:
	// Bytes written: 3
	// Items: [hello world streams]
}

⬆️ Back to Top


⬆️ Back to Top


🔞 Zero

Zero-value utilities and byte-to-string conversion functions.

Functions

zero B2S

ExampleB2S demonstrates converting []byte to string without memory allocation

Code
func ExampleB2S() {
	// Convert []byte to string using zero-allocation conversion
	b := []byte("Hello, Gophers!")
	s := B2S(b)

	fmt.Printf("Original bytes: %v\n", b)
	fmt.Printf("Converted to string: %s\n", s)
	fmt.Printf("Length: %d\n", len(s))
	fmt.Printf(
		"Same underlying data: %t\n",
		uintptr(unsafe.Pointer(&b[0])) == uintptr(unsafe.Pointer(unsafe.StringData(s))),
	)

	// Output:
	// Original bytes: [72 101 108 108 111 44 32 71 111 112 104 101 114 115 33]
	// Converted to string: Hello, Gophers!
	// Length: 15
	// Same underlying data: true
}

⬆️ Back to Top


zero S2B

ExampleS2B demonstrates converting a string to []byte without memory allocation

Code
func ExampleS2B() {
	// Convert string to []byte using zero-allocation conversion
	s := "Hello, World!"
	b := S2B(s)

	fmt.Printf("Original string: %s\n", s)
	fmt.Printf("Converted to bytes: %v\n", b)
	fmt.Printf("Bytes as string: %s\n", string(b))
	fmt.Printf(
		"Same underlying data: %t\n",
		uintptr(unsafe.Pointer(unsafe.StringData(s))) == uintptr(unsafe.Pointer(&b[0])),
	)

	// Output:
	// Original string: Hello, World!
	// Converted to bytes: [72 101 108 108 111 44 32 87 111 114 108 100 33]
	// Bytes as string: Hello, World!
	// Same underlying data: true
}

⬆️ Back to Top


⬆️ Back to Top


About

A practical Go toolkit with generic utilities for working with slices, maps, and functional programming primitives, streams, databases and more

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors