valueextractor

package module
v1.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 12, 2024 License: MIT Imports: 6 Imported by: 0

README

Value Extractor

GitHub go.mod Go version Go Report Card GitHub license GitHub stars GitHub forks Go Reference

This package provides a flexible system for extracting values from various sources (like HTTP requests, maps, etc.) and converting them into the desired Go types with comprehensive error handling. It's designed to make it easier to work with dynamic data sources in a type-safe manner.

Features

  • Extensible Value Extraction: Supports extracting values from maps, HTTP request query parameters, and form data.
  • Type Conversion: Convert extracted strings into specific Go types (string, uint64, int64, float64, bool), including custom type conversions.
  • Direct Return Types: Provides direct return functions (ReturnString, ReturnUint64, etc.) for performance optimization.
  • Error Handling: Collects and aggregates errors throughout the extraction and conversion process for robust error reporting.
  • No external dependencies - only the Go standard library.
  • Fast - run go test -bench .. It's between 20-40% faster than the idiomatic struct tag + reflection.
  • Lighweight - Less than 300 LOC.
  • Easy to read - Only 1 if err != nil for all of your conversions.

Getting Started

Installation
go get github.com/Howard3/valueextractor
Basic Usage

Here are quick examples to get you started:

There are three main ways to use this library:

  • References
  • Direct value return objects
  • Return Generics
Using References
package main

import (
    "fmt"
    "net/http"
    "github.com/Howard3/valueextractor"
)

func main() {
    // Initialize the extractor with optional keys using the new fluent interface
    req, _ := http.NewRequest("GET", "/?id=123&name=John&age=30", nil)
    ex := valueextractor.Using(valueextractor.QueryExtractor{Query: req.URL.Query()}, valueextractor.WithOptionalKeys("age", "foo"))

    var id uint64
    var name string
    var age uint64 // Note: 'age' is treated as an optional parameter
    ex.With("id", valueextractor.AsUint64(&id))
    ex.With("name", valueextractor.AsString(&name))
    ex.With("age", valueextractor.AsUint64(&age)) // No error if 'age' is missing

    if err := ex.Errors(); err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Printf("Extracted values - ID: %d, Name: %s, Age: %d\n", id, name, age)
    }
}
Fluent Initialization with Optional Keys

The Using function supports a fluent interface for specifying optional keys. This is achieved using the WithOptionalKeys function, which modifies the extractor's behavior to treat certain keys as optional during value extraction. If these keys are missing from the source, their absence will not contribute to the error collection, simplifying error handling for optional data.

ex := valueextractor.Using(QueryExtractor{Query: req.URL.Query()}, valueextractor.WithOptionalKeys("age", "foo"))

This approach allows you to declaratively specify which keys are optional, enhancing code readability and reducing the boilerplate associated with optional value handling.

Using Direct Return Functions
package main

import (
    "fmt"
    "github.com/Howard3/valueextractor"
)

func main() {
    ex := valueextractor.NewExtractor(...) // Assume ex is properly initialized

    if *valueextractor.ReturnString(ex, "name") != "John" {
        fmt.Println("Name not parsed correctly")
    }

    if *valueextractor.ReturnUint64(ex, "age") != 30 {
        fmt.Println("Age not parsed correctly")
    }
}
Using Return Generics

Return generics are easy to work with but have approximately the same performance as the struct+reflection approach.

package main

import (
    "fmt"
    "net/http"
    "github.com/Howard3/valueextractor"
)

func main() {
    // Example: Extracting values from a query parameter
    req, _ := http.NewRequest("GET", "/?id=123&name=John", nil)
    queryExtractor := valueextractor.QueryExtractor{Query: req.URL.Query()}

    ex := valueextractor.Using(queryExtractor)
    id := valueextractor.Result(ex, "id", valueextractor.AsUint64)
    name := valueextractor.Result(ex, "name", valueextractor.AsString)

    if err := ex.Errors(); err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Printf("Extracted values - ID: %d, Name: %s\n", id, name)
    }
}

Extensibility

The system is designed with extensibility in mind. You can extend it by implementing custom ValueExtractor interfaces or Converter functions. See the documentation for details on creating custom extractors and converters.

Implementing a Custom ValueExtractor

To extract values from a new data source, implement the ValueExtractor interface:

type CustomExtractor struct {}

func (ce CustomExtractor) Get(key string) (string, error) {
    // Logic to extract and return the value based on the key
}
Adding a New Converter Function

To support converting to a new type:

func AsCustomType(ref *CustomType) valueextractor.Converter {
    return func(ec *valueextractor.Extractor, value string) error {
        // Convert value to CustomType and assign to ref
        
        *ref = newVal // assign the new value

        return nil
    }
}

Error Handling

Errors are collected throughout the extraction and conversion process. Use the Errors method to retrieve any accumulated errors. The package defines ErrNotFound for missing keys and provides detailed error types for extract and convert errors, allowing precise error handling and diagnostics.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("key not found")

ErrNotFound is an error that is returned when a key is not found

View Source
var ErrRequestNil = errors.New("request is nil")

ErrRequestNil is an error that is returned when the request is nil

View Source
var ErrRequestParseForm = errors.New("error parsing form")

Functions

func Result

func Result[T any](ex *Extractor, key string, converter ResultConverter[T]) T

Result is a function that extracts a value from the request and converts it to the desired type It offers a simpler API than the With function NOTE: this is a convenience function but is slower than using the With function directly the performance is about on par with the traditional struct+reflection approach

func ResultPtr added in v1.0.1

func ResultPtr[T any](ex *Extractor, key string, converter ResultConverter[T]) *T

ResultPtr is a function that extracts a value from the request and converts it to the desired type It offers a simpler API than the With function, but returns a pointer to the result instead of the result itself NOTE: this is a convenience function but is slower than using the With function directly the performance is about on par with the traditional struct+reflection approach

func ReturnBool added in v1.0.2

func ReturnBool(ec *Extractor, key string) *bool

ReturnBool is a function that returns a bool

func ReturnFloat64 added in v1.0.2

func ReturnFloat64(ec *Extractor, key string) *float64

ReturnFloat64 is a function that returns a float64

func ReturnInt64 added in v1.0.2

func ReturnInt64(ec *Extractor, key string) *int64

ReturnInt64 is a function that returns an int64

func ReturnString added in v1.0.2

func ReturnString(ec *Extractor, key string) *string

func ReturnUint64 added in v1.0.2

func ReturnUint64(ec *Extractor, key string) *uint64

ReturnUint64 is a function that returns a uint64

func WithOptionalKeys added in v1.1.0

func WithOptionalKeys(keys ...string) func(*Extractor)

Types

type Converter

type Converter func(ec *Extractor, value string) error

Converter is a function that takes an Extractor and a key and returns a value and an error

func AsBool added in v1.0.2

func AsBool(ref *bool) Converter

AsBool is a function that converts a string to a bool

func AsFloat64 added in v1.0.2

func AsFloat64(ref *float64) Converter

AsFloat64 is a function that converts a string to a float64

func AsInt64

func AsInt64(ref *int64) Converter

AsInt64 is a function that converts a string to an int64

func AsString

func AsString(ref *string) Converter

AsString maintains the value as a string, just allowing extraction

func AsUint64

func AsUint64(ref *uint64) Converter

AsUint is a function that converts a string to a uint64

type DirectReturnType added in v1.1.0

type DirectReturnType func(ec *Extractor, key string) interface{}

DirectReturnType is a function that takes an Extractor and a key and returns a value this is a more performant alternative to the Result generic.

type Error

type Error struct {
	// contains filtered or unexported fields
}

Error is a custom error type that is used to represent errors that occur during the extraction and conversion of values.

func NewConvertError

func NewConvertError(key string, err error) *Error

NewConvertError creates a new ConvertError.

func NewExtractError

func NewExtractError(key string, err error) *Error

NewExtractError creates a new ExtractError.

func (Error) Error

func (e Error) Error() string

Error returns the error message.

func (Error) IsConvertError

func (e Error) IsConvertError() bool

IsConvertError returns true if the error is of type ConvertError.

func (Error) IsExtractError

func (e Error) IsExtractError() bool

IsExtractError returns true if the error is of type ExtractError.

func (Error) Key

func (e Error) Key() string

Key returns the key that was used to extract the value.

type ErrorType

type ErrorType int
const (
	ExtractError ErrorType = iota
	ConvertError
)

type Extractor

type Extractor struct {
	// contains filtered or unexported fields
}

Extractor is a value extractor that can be used to extract values from a request and type-convert them to the desired type, collecting errors along the way

func Using

func Using(extractor ValueExtractor, options ...func(*Extractor)) *Extractor

Using creates a new Extractor with the given value extractor A value extractor is a function that takes a key and returns a value and an error, if any

func (*Extractor) AddConvertError

func (ec *Extractor) AddConvertError(key string, err error)

AddConvertError adds an error to the chain

func (*Extractor) AddExtractError

func (ec *Extractor) AddExtractError(key string, err error)

AddExtractError adds an error to the chain

func (*Extractor) Errors

func (ec *Extractor) Errors() []*Error

Errors returns an error if there are any errors in the parser

func (*Extractor) JoinedErrors

func (ec *Extractor) JoinedErrors() error

JoinedErrors returns a single error with all the errors JoinedErrors

func (*Extractor) With

func (ec *Extractor) With(key string, converter Converter)

With taks a key and a converter and extracts the value from the request

type FormExtractor

type FormExtractor struct {
	Request *http.Request
	// contains filtered or unexported fields
}

FormExtractor is a value extractor that extracts values from a http request's form

func (*FormExtractor) Get

func (fe *FormExtractor) Get(key string) (string, error)

Get returns the value of a form parameter from the Request

type MapExtractor

type MapExtractor map[string]string

MapExtractor is a value extractor that extracts values from a map

func (MapExtractor) Get

func (m MapExtractor) Get(key string) (string, error)

Get returns the value of a key from the map

type QueryExtractor

type QueryExtractor struct {
	Query url.Values
}

QueryExtractor is a value extractor that extracts values from a http request's query parameters

func (QueryExtractor) Get

func (qe QueryExtractor) Get(key string) (string, error)

Get returns the value of a query parameter from the request

type ResultConverter

type ResultConverter[T any] func(*T) Converter

ResultConverter defines a wrapped converter with input argument as a reference that returns a converter function. It's intended to be used with the Result function

type ValueExtractor

type ValueExtractor interface {
	Get(key string) (val string, err error)
}

extractors

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL