mirror of
https://github.com/mainflux/mainflux.git
synced 2025-05-02 22:17:10 +08:00

* Return Auth service Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update Compose to run with SpiceDB and Auth svc Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update auth gRPC API Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Remove Users' policies Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Move Groups to internal Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Use shared groups in Users Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Remove unused code Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Use pkg Groups in Things Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Remove Things groups Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Make imports consistent Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update Groups networking Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Remove things groups-specific API Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Move Things Clients to the root Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Move Clients to Users root Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Temporarily remove tracing Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Fix imports Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Add buffer config for gRPC Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update auth type for Things Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Use Auth for login Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Add temporary solution for refresh token Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update Tokenizer interface Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Updade tokens issuing Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Fix token issuing Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update JWT validator and refactor Tokenizer Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Rename access timeout Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Rename login to authenticate Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update Identify to use SubjectID Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Add Auth to Groups Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Use the Auth service for Groups Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update auth schema Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Fix Auth for Groups Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Add auth for addons (#14) Signed-off-by: Arvindh <arvindh91@gmail.com> Speparate Login and Refresh tokens Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Merge authN and authZ requests for things Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Add connect and disconnect Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update sharing Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Fix policies addition and removal Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Update relation with roels Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Add gRPC to Things Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Assign and Unassign members to group and Listing of Group members (#15) * add auth for addons Signed-off-by: Arvindh <arvindh91@gmail.com> * add assign and unassign to group Signed-off-by: Arvindh <arvindh91@gmail.com> * add group incomplete repo implementation Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Move coap mqtt and ws policies to spicedb (#16) Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Remove old policies Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> NOISSUE - Things authorize to return thingID (#18) This commit modifies the authorize endpoint to the grpc endpoint to return thingID. The authorize endpoint allows adapters to get the publisher of the message. Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Add Groups to users service (#17) * add assign and unassign to group Signed-off-by: Arvindh <arvindh91@gmail.com> * add group incomplete repo implementation Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users stable 1 Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users stable 2 Signed-off-by: Arvindh <arvindh91@gmail.com> * groups for users & things Signed-off-by: Arvindh <arvindh91@gmail.com> * Amend signature Signed-off-by: Arvindh <arvindh91@gmail.com> * fix merge error Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Fix es code (#21) Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Fix Bugs (#20) * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Test e2e (#19) * fix: connect method Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * fix: e2e Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * fix changes in sdk and e2e Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * feat(docker): remove unnecessary port mapping Remove the port mapping for MQTT broker in the docker-compose.yml file. Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * Enable group listing Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * feat(responses): update ChannelsPage struct The ChannelsPage struct in the responses.go file has been updated. The "Channels" field has been renamed to "Groups" to provide more accurate naming. This change ensures consistency and clarity in the codebase. Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * feat(things): add UpdateClientSecret method Add the UpdateClientSecret method to the things service. This method allows updating the client secret for a specific client identified by the provided token, id, and key parameters. Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> --------- Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Use smaller buffers for gRPC Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Clean up tests (#22) Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add Connect Disconnect endpoints (#23) * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> * fix bugs Signed-off-by: Arvindh <arvindh91@gmail.com> * fix list of things in a channel and Add connect disconnect endpoint Signed-off-by: Arvindh <arvindh91@gmail.com> * fix list of things in a channel and Add connect disconnect endpoint Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add: Things share with users (#25) * fix list of things in a channel and Add connect disconnect endpoint Signed-off-by: Arvindh <arvindh91@gmail.com> * add: things share with other users Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Rename gRPC Services (#24) * Rename things and users auth service Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * docs: add authorization docs for gRPC services Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * Rename things and users grpc services Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * Remove mainflux.env package Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> --------- Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add: Listing of things, channels, groups, users (#26) * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> * add: listing of channels, users, groups, things Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Clean Up Users (#27) * feat(groups): rename redis package to events - Renamed the `redis` package to `events` in the `internal/groups` directory. - Updated the file paths and names accordingly. - This change reflects the more accurate purpose of the package and improves code organization. Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * feat(auth): Modify identity method Change request and response of identity method Add accessToken and refreshToken to Token response Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * clean up users, remove dead code Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * feat(users): add unit tests for user service This commit adds unit tests for the user service in the `users` package. The tests cover various scenarios and ensure the correct behavior of the service. Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> --------- Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Add: List of user groups & removed repeating code in groups (#29) * removed repeating code in list groups Signed-off-by: Arvindh <arvindh91@gmail.com> * add: list of user group Signed-off-by: Arvindh <arvindh91@gmail.com> * fix: otel handler operator name for endpoints Signed-off-by: Arvindh <arvindh91@gmail.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Clean Up Things Service (#28) * Rework things service Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * add tests Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> --------- Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Clean Up Auth Service (#30) * clean up auth service Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> * feat(auth): remove unused import Remove the unused import of `emptypb` in `auth.pb.go`. This import is not being used in the codebase and can be safely removed. Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> --------- Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * NOISSUE - Update API docs (#31) Signed-off-by: rodneyosodo <blackd0t@protonmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Remove TODO comments and cleanup the code Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> * Update dependenices Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> --------- Signed-off-by: Arvindh <arvindh91@gmail.com> Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com> Signed-off-by: Rodney Osodo <28790446+rodneyosodo@users.noreply.github.com> Signed-off-by: rodneyosodo <blackd0t@protonmail.com> Co-authored-by: b1ackd0t <28790446+rodneyosodo@users.noreply.github.com> Co-authored-by: Arvindh <30824765+arvindh123@users.noreply.github.com>
1332 lines
43 KiB
Go
1332 lines
43 KiB
Go
package echo
|
|
|
|
import (
|
|
"encoding"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
/**
|
|
Following functions provide handful of methods for binding to Go native types from request query or path parameters.
|
|
* QueryParamsBinder(c) - binds query parameters (source URL)
|
|
* PathParamsBinder(c) - binds path parameters (source URL)
|
|
* FormFieldBinder(c) - binds form fields (source URL + body)
|
|
|
|
Example:
|
|
```go
|
|
var length int64
|
|
err := echo.QueryParamsBinder(c).Int64("length", &length).BindError()
|
|
```
|
|
|
|
For every supported type there are following methods:
|
|
* <Type>("param", &destination) - if parameter value exists then binds it to given destination of that type i.e Int64(...).
|
|
* Must<Type>("param", &destination) - parameter value is required to exist, binds it to given destination of that type i.e MustInt64(...).
|
|
* <Type>s("param", &destination) - (for slices) if parameter values exists then binds it to given destination of that type i.e Int64s(...).
|
|
* Must<Type>s("param", &destination) - (for slices) parameter value is required to exist, binds it to given destination of that type i.e MustInt64s(...).
|
|
|
|
for some slice types `BindWithDelimiter("param", &dest, ",")` supports splitting parameter values before type conversion is done
|
|
i.e. URL `/api/search?id=1,2,3&id=1` can be bind to `[]int64{1,2,3,1}`
|
|
|
|
`FailFast` flags binder to stop binding after first bind error during binder call chain. Enabled by default.
|
|
`BindError()` returns first bind error from binder and resets errors in binder. Useful along with `FailFast()` method
|
|
to do binding and returns on first problem
|
|
`BindErrors()` returns all bind errors from binder and resets errors in binder.
|
|
|
|
Types that are supported:
|
|
* bool
|
|
* float32
|
|
* float64
|
|
* int
|
|
* int8
|
|
* int16
|
|
* int32
|
|
* int64
|
|
* uint
|
|
* uint8/byte (does not support `bytes()`. Use BindUnmarshaler/CustomFunc to convert value from base64 etc to []byte{})
|
|
* uint16
|
|
* uint32
|
|
* uint64
|
|
* string
|
|
* time
|
|
* duration
|
|
* BindUnmarshaler() interface
|
|
* TextUnmarshaler() interface
|
|
* JSONUnmarshaler() interface
|
|
* UnixTime() - converts unix time (integer) to time.Time
|
|
* UnixTimeMilli() - converts unix time with millisecond precision (integer) to time.Time
|
|
* UnixTimeNano() - converts unix time with nanosecond precision (integer) to time.Time
|
|
* CustomFunc() - callback function for your custom conversion logic. Signature `func(values []string) []error`
|
|
*/
|
|
|
|
// BindingError represents an error that occurred while binding request data.
|
|
type BindingError struct {
|
|
// Field is the field name where value binding failed
|
|
Field string `json:"field"`
|
|
// Values of parameter that failed to bind.
|
|
Values []string `json:"-"`
|
|
*HTTPError
|
|
}
|
|
|
|
// NewBindingError creates new instance of binding error
|
|
func NewBindingError(sourceParam string, values []string, message interface{}, internalError error) error {
|
|
return &BindingError{
|
|
Field: sourceParam,
|
|
Values: values,
|
|
HTTPError: &HTTPError{
|
|
Code: http.StatusBadRequest,
|
|
Message: message,
|
|
Internal: internalError,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Error returns error message
|
|
func (be *BindingError) Error() string {
|
|
return fmt.Sprintf("%s, field=%s", be.HTTPError.Error(), be.Field)
|
|
}
|
|
|
|
// ValueBinder provides utility methods for binding query or path parameter to various Go built-in types
|
|
type ValueBinder struct {
|
|
// failFast is flag for binding methods to return without attempting to bind when previous binding already failed
|
|
failFast bool
|
|
errors []error
|
|
|
|
// ValueFunc is used to get single parameter (first) value from request
|
|
ValueFunc func(sourceParam string) string
|
|
// ValuesFunc is used to get all values for parameter from request. i.e. `/api/search?ids=1&ids=2`
|
|
ValuesFunc func(sourceParam string) []string
|
|
// ErrorFunc is used to create errors. Allows you to use your own error type, that for example marshals to your specific json response
|
|
ErrorFunc func(sourceParam string, values []string, message interface{}, internalError error) error
|
|
}
|
|
|
|
// QueryParamsBinder creates query parameter value binder
|
|
func QueryParamsBinder(c Context) *ValueBinder {
|
|
return &ValueBinder{
|
|
failFast: true,
|
|
ValueFunc: c.QueryParam,
|
|
ValuesFunc: func(sourceParam string) []string {
|
|
values, ok := c.QueryParams()[sourceParam]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return values
|
|
},
|
|
ErrorFunc: NewBindingError,
|
|
}
|
|
}
|
|
|
|
// PathParamsBinder creates path parameter value binder
|
|
func PathParamsBinder(c Context) *ValueBinder {
|
|
return &ValueBinder{
|
|
failFast: true,
|
|
ValueFunc: c.Param,
|
|
ValuesFunc: func(sourceParam string) []string {
|
|
// path parameter should not have multiple values so getting values does not make sense but lets not error out here
|
|
value := c.Param(sourceParam)
|
|
if value == "" {
|
|
return nil
|
|
}
|
|
return []string{value}
|
|
},
|
|
ErrorFunc: NewBindingError,
|
|
}
|
|
}
|
|
|
|
// FormFieldBinder creates form field value binder
|
|
// For all requests, FormFieldBinder parses the raw query from the URL and uses query params as form fields
|
|
//
|
|
// For POST, PUT, and PATCH requests, it also reads the request body, parses it
|
|
// as a form and uses query params as form fields. Request body parameters take precedence over URL query
|
|
// string values in r.Form.
|
|
//
|
|
// NB: when binding forms take note that this implementation uses standard library form parsing
|
|
// which parses form data from BOTH URL and BODY if content type is not MIMEMultipartForm
|
|
// See https://golang.org/pkg/net/http/#Request.ParseForm
|
|
func FormFieldBinder(c Context) *ValueBinder {
|
|
vb := &ValueBinder{
|
|
failFast: true,
|
|
ValueFunc: func(sourceParam string) string {
|
|
return c.Request().FormValue(sourceParam)
|
|
},
|
|
ErrorFunc: NewBindingError,
|
|
}
|
|
vb.ValuesFunc = func(sourceParam string) []string {
|
|
if c.Request().Form == nil {
|
|
// this is same as `Request().FormValue()` does internally
|
|
_ = c.Request().ParseMultipartForm(32 << 20)
|
|
}
|
|
values, ok := c.Request().Form[sourceParam]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return values
|
|
}
|
|
|
|
return vb
|
|
}
|
|
|
|
// FailFast set internal flag to indicate if binding methods will return early (without binding) when previous bind failed
|
|
// NB: call this method before any other binding methods as it modifies binding methods behaviour
|
|
func (b *ValueBinder) FailFast(value bool) *ValueBinder {
|
|
b.failFast = value
|
|
return b
|
|
}
|
|
|
|
func (b *ValueBinder) setError(err error) {
|
|
if b.errors == nil {
|
|
b.errors = []error{err}
|
|
return
|
|
}
|
|
b.errors = append(b.errors, err)
|
|
}
|
|
|
|
// BindError returns first seen bind error and resets/empties binder errors for further calls
|
|
func (b *ValueBinder) BindError() error {
|
|
if b.errors == nil {
|
|
return nil
|
|
}
|
|
err := b.errors[0]
|
|
b.errors = nil // reset errors so next chain will start from zero
|
|
return err
|
|
}
|
|
|
|
// BindErrors returns all bind errors and resets/empties binder errors for further calls
|
|
func (b *ValueBinder) BindErrors() []error {
|
|
if b.errors == nil {
|
|
return nil
|
|
}
|
|
errors := b.errors
|
|
b.errors = nil // reset errors so next chain will start from zero
|
|
return errors
|
|
}
|
|
|
|
// CustomFunc binds parameter values with Func. Func is called only when parameter values exist.
|
|
func (b *ValueBinder) CustomFunc(sourceParam string, customFunc func(values []string) []error) *ValueBinder {
|
|
return b.customFunc(sourceParam, customFunc, false)
|
|
}
|
|
|
|
// MustCustomFunc requires parameter values to exist to bind with Func. Returns error when value does not exist.
|
|
func (b *ValueBinder) MustCustomFunc(sourceParam string, customFunc func(values []string) []error) *ValueBinder {
|
|
return b.customFunc(sourceParam, customFunc, true)
|
|
}
|
|
|
|
func (b *ValueBinder) customFunc(sourceParam string, customFunc func(values []string) []error, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
if errs := customFunc(values); errs != nil {
|
|
b.errors = append(b.errors, errs...)
|
|
}
|
|
return b
|
|
}
|
|
|
|
// String binds parameter to string variable
|
|
func (b *ValueBinder) String(sourceParam string, dest *string) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
return b
|
|
}
|
|
*dest = value
|
|
return b
|
|
}
|
|
|
|
// MustString requires parameter value to exist to bind to string variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustString(sourceParam string, dest *string) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
|
|
return b
|
|
}
|
|
*dest = value
|
|
return b
|
|
}
|
|
|
|
// Strings binds parameter values to slice of string
|
|
func (b *ValueBinder) Strings(sourceParam string, dest *[]string) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValuesFunc(sourceParam)
|
|
if value == nil {
|
|
return b
|
|
}
|
|
*dest = value
|
|
return b
|
|
}
|
|
|
|
// MustStrings requires parameter values to exist to bind to slice of string variables. Returns error when value does not exist
|
|
func (b *ValueBinder) MustStrings(sourceParam string, dest *[]string) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValuesFunc(sourceParam)
|
|
if value == nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
return b
|
|
}
|
|
*dest = value
|
|
return b
|
|
}
|
|
|
|
// BindUnmarshaler binds parameter to destination implementing BindUnmarshaler interface
|
|
func (b *ValueBinder) BindUnmarshaler(sourceParam string, dest BindUnmarshaler) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
tmp := b.ValueFunc(sourceParam)
|
|
if tmp == "" {
|
|
return b
|
|
}
|
|
|
|
if err := dest.UnmarshalParam(tmp); err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to BindUnmarshaler interface", err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
// MustBindUnmarshaler requires parameter value to exist to bind to destination implementing BindUnmarshaler interface.
|
|
// Returns error when value does not exist
|
|
func (b *ValueBinder) MustBindUnmarshaler(sourceParam string, dest BindUnmarshaler) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
|
|
return b
|
|
}
|
|
|
|
if err := dest.UnmarshalParam(value); err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to BindUnmarshaler interface", err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
// JSONUnmarshaler binds parameter to destination implementing json.Unmarshaler interface
|
|
func (b *ValueBinder) JSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
tmp := b.ValueFunc(sourceParam)
|
|
if tmp == "" {
|
|
return b
|
|
}
|
|
|
|
if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
// MustJSONUnmarshaler requires parameter value to exist to bind to destination implementing json.Unmarshaler interface.
|
|
// Returns error when value does not exist
|
|
func (b *ValueBinder) MustJSONUnmarshaler(sourceParam string, dest json.Unmarshaler) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
tmp := b.ValueFunc(sourceParam)
|
|
if tmp == "" {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
|
|
return b
|
|
}
|
|
|
|
if err := dest.UnmarshalJSON([]byte(tmp)); err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to json.Unmarshaler interface", err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
// TextUnmarshaler binds parameter to destination implementing encoding.TextUnmarshaler interface
|
|
func (b *ValueBinder) TextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
tmp := b.ValueFunc(sourceParam)
|
|
if tmp == "" {
|
|
return b
|
|
}
|
|
|
|
if err := dest.UnmarshalText([]byte(tmp)); err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
// MustTextUnmarshaler requires parameter value to exist to bind to destination implementing encoding.TextUnmarshaler interface.
|
|
// Returns error when value does not exist
|
|
func (b *ValueBinder) MustTextUnmarshaler(sourceParam string, dest encoding.TextUnmarshaler) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
tmp := b.ValueFunc(sourceParam)
|
|
if tmp == "" {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "required field value is empty", nil))
|
|
return b
|
|
}
|
|
|
|
if err := dest.UnmarshalText([]byte(tmp)); err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{tmp}, "failed to bind field value to encoding.TextUnmarshaler interface", err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
// BindWithDelimiter binds parameter to destination by suitable conversion function.
|
|
// Delimiter is used before conversion to split parameter value to separate values
|
|
func (b *ValueBinder) BindWithDelimiter(sourceParam string, dest interface{}, delimiter string) *ValueBinder {
|
|
return b.bindWithDelimiter(sourceParam, dest, delimiter, false)
|
|
}
|
|
|
|
// MustBindWithDelimiter requires parameter value to exist to bind destination by suitable conversion function.
|
|
// Delimiter is used before conversion to split parameter value to separate values
|
|
func (b *ValueBinder) MustBindWithDelimiter(sourceParam string, dest interface{}, delimiter string) *ValueBinder {
|
|
return b.bindWithDelimiter(sourceParam, dest, delimiter, true)
|
|
}
|
|
|
|
func (b *ValueBinder) bindWithDelimiter(sourceParam string, dest interface{}, delimiter string, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
tmpValues := make([]string, 0, len(values))
|
|
for _, v := range values {
|
|
tmpValues = append(tmpValues, strings.Split(v, delimiter)...)
|
|
}
|
|
|
|
switch d := dest.(type) {
|
|
case *[]string:
|
|
*d = tmpValues
|
|
return b
|
|
case *[]bool:
|
|
return b.bools(sourceParam, tmpValues, d)
|
|
case *[]int64, *[]int32, *[]int16, *[]int8, *[]int:
|
|
return b.ints(sourceParam, tmpValues, d)
|
|
case *[]uint64, *[]uint32, *[]uint16, *[]uint8, *[]uint: // *[]byte is same as *[]uint8
|
|
return b.uints(sourceParam, tmpValues, d)
|
|
case *[]float64, *[]float32:
|
|
return b.floats(sourceParam, tmpValues, d)
|
|
case *[]time.Duration:
|
|
return b.durations(sourceParam, tmpValues, d)
|
|
default:
|
|
// support only cases when destination is slice
|
|
// does not support time.Time as it needs argument (layout) for parsing or BindUnmarshaler
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "unsupported bind type", nil))
|
|
return b
|
|
}
|
|
}
|
|
|
|
// Int64 binds parameter to int64 variable
|
|
func (b *ValueBinder) Int64(sourceParam string, dest *int64) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 64, false)
|
|
}
|
|
|
|
// MustInt64 requires parameter value to exist to bind to int64 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt64(sourceParam string, dest *int64) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 64, true)
|
|
}
|
|
|
|
// Int32 binds parameter to int32 variable
|
|
func (b *ValueBinder) Int32(sourceParam string, dest *int32) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 32, false)
|
|
}
|
|
|
|
// MustInt32 requires parameter value to exist to bind to int32 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt32(sourceParam string, dest *int32) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 32, true)
|
|
}
|
|
|
|
// Int16 binds parameter to int16 variable
|
|
func (b *ValueBinder) Int16(sourceParam string, dest *int16) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 16, false)
|
|
}
|
|
|
|
// MustInt16 requires parameter value to exist to bind to int16 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt16(sourceParam string, dest *int16) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 16, true)
|
|
}
|
|
|
|
// Int8 binds parameter to int8 variable
|
|
func (b *ValueBinder) Int8(sourceParam string, dest *int8) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 8, false)
|
|
}
|
|
|
|
// MustInt8 requires parameter value to exist to bind to int8 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt8(sourceParam string, dest *int8) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 8, true)
|
|
}
|
|
|
|
// Int binds parameter to int variable
|
|
func (b *ValueBinder) Int(sourceParam string, dest *int) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 0, false)
|
|
}
|
|
|
|
// MustInt requires parameter value to exist to bind to int variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt(sourceParam string, dest *int) *ValueBinder {
|
|
return b.intValue(sourceParam, dest, 0, true)
|
|
}
|
|
|
|
func (b *ValueBinder) intValue(sourceParam string, dest interface{}, bitSize int, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
|
|
return b.int(sourceParam, value, dest, bitSize)
|
|
}
|
|
|
|
func (b *ValueBinder) int(sourceParam string, value string, dest interface{}, bitSize int) *ValueBinder {
|
|
n, err := strconv.ParseInt(value, 10, bitSize)
|
|
if err != nil {
|
|
if bitSize == 0 {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to int", err))
|
|
} else {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, fmt.Sprintf("failed to bind field value to int%v", bitSize), err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
switch d := dest.(type) {
|
|
case *int64:
|
|
*d = n
|
|
case *int32:
|
|
*d = int32(n)
|
|
case *int16:
|
|
*d = int16(n)
|
|
case *int8:
|
|
*d = int8(n)
|
|
case *int:
|
|
*d = int(n)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (b *ValueBinder) intsValue(sourceParam string, dest interface{}, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, values, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
return b.ints(sourceParam, values, dest)
|
|
}
|
|
|
|
func (b *ValueBinder) ints(sourceParam string, values []string, dest interface{}) *ValueBinder {
|
|
switch d := dest.(type) {
|
|
case *[]int64:
|
|
tmp := make([]int64, len(values))
|
|
for i, v := range values {
|
|
b.int(sourceParam, v, &tmp[i], 64)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]int32:
|
|
tmp := make([]int32, len(values))
|
|
for i, v := range values {
|
|
b.int(sourceParam, v, &tmp[i], 32)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]int16:
|
|
tmp := make([]int16, len(values))
|
|
for i, v := range values {
|
|
b.int(sourceParam, v, &tmp[i], 16)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]int8:
|
|
tmp := make([]int8, len(values))
|
|
for i, v := range values {
|
|
b.int(sourceParam, v, &tmp[i], 8)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]int:
|
|
tmp := make([]int, len(values))
|
|
for i, v := range values {
|
|
b.int(sourceParam, v, &tmp[i], 0)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Int64s binds parameter to slice of int64
|
|
func (b *ValueBinder) Int64s(sourceParam string, dest *[]int64) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustInt64s requires parameter value to exist to bind to int64 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt64s(sourceParam string, dest *[]int64) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Int32s binds parameter to slice of int32
|
|
func (b *ValueBinder) Int32s(sourceParam string, dest *[]int32) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustInt32s requires parameter value to exist to bind to int32 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt32s(sourceParam string, dest *[]int32) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Int16s binds parameter to slice of int16
|
|
func (b *ValueBinder) Int16s(sourceParam string, dest *[]int16) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustInt16s requires parameter value to exist to bind to int16 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt16s(sourceParam string, dest *[]int16) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Int8s binds parameter to slice of int8
|
|
func (b *ValueBinder) Int8s(sourceParam string, dest *[]int8) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustInt8s requires parameter value to exist to bind to int8 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInt8s(sourceParam string, dest *[]int8) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Ints binds parameter to slice of int
|
|
func (b *ValueBinder) Ints(sourceParam string, dest *[]int) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustInts requires parameter value to exist to bind to int slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustInts(sourceParam string, dest *[]int) *ValueBinder {
|
|
return b.intsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Uint64 binds parameter to uint64 variable
|
|
func (b *ValueBinder) Uint64(sourceParam string, dest *uint64) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 64, false)
|
|
}
|
|
|
|
// MustUint64 requires parameter value to exist to bind to uint64 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint64(sourceParam string, dest *uint64) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 64, true)
|
|
}
|
|
|
|
// Uint32 binds parameter to uint32 variable
|
|
func (b *ValueBinder) Uint32(sourceParam string, dest *uint32) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 32, false)
|
|
}
|
|
|
|
// MustUint32 requires parameter value to exist to bind to uint32 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint32(sourceParam string, dest *uint32) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 32, true)
|
|
}
|
|
|
|
// Uint16 binds parameter to uint16 variable
|
|
func (b *ValueBinder) Uint16(sourceParam string, dest *uint16) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 16, false)
|
|
}
|
|
|
|
// MustUint16 requires parameter value to exist to bind to uint16 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint16(sourceParam string, dest *uint16) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 16, true)
|
|
}
|
|
|
|
// Uint8 binds parameter to uint8 variable
|
|
func (b *ValueBinder) Uint8(sourceParam string, dest *uint8) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 8, false)
|
|
}
|
|
|
|
// MustUint8 requires parameter value to exist to bind to uint8 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint8(sourceParam string, dest *uint8) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 8, true)
|
|
}
|
|
|
|
// Byte binds parameter to byte variable
|
|
func (b *ValueBinder) Byte(sourceParam string, dest *byte) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 8, false)
|
|
}
|
|
|
|
// MustByte requires parameter value to exist to bind to byte variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustByte(sourceParam string, dest *byte) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 8, true)
|
|
}
|
|
|
|
// Uint binds parameter to uint variable
|
|
func (b *ValueBinder) Uint(sourceParam string, dest *uint) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 0, false)
|
|
}
|
|
|
|
// MustUint requires parameter value to exist to bind to uint variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint(sourceParam string, dest *uint) *ValueBinder {
|
|
return b.uintValue(sourceParam, dest, 0, true)
|
|
}
|
|
|
|
func (b *ValueBinder) uintValue(sourceParam string, dest interface{}, bitSize int, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
|
|
return b.uint(sourceParam, value, dest, bitSize)
|
|
}
|
|
|
|
func (b *ValueBinder) uint(sourceParam string, value string, dest interface{}, bitSize int) *ValueBinder {
|
|
n, err := strconv.ParseUint(value, 10, bitSize)
|
|
if err != nil {
|
|
if bitSize == 0 {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to uint", err))
|
|
} else {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, fmt.Sprintf("failed to bind field value to uint%v", bitSize), err))
|
|
}
|
|
return b
|
|
}
|
|
|
|
switch d := dest.(type) {
|
|
case *uint64:
|
|
*d = n
|
|
case *uint32:
|
|
*d = uint32(n)
|
|
case *uint16:
|
|
*d = uint16(n)
|
|
case *uint8: // byte is alias to uint8
|
|
*d = uint8(n)
|
|
case *uint:
|
|
*d = uint(n)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (b *ValueBinder) uintsValue(sourceParam string, dest interface{}, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, values, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
return b.uints(sourceParam, values, dest)
|
|
}
|
|
|
|
func (b *ValueBinder) uints(sourceParam string, values []string, dest interface{}) *ValueBinder {
|
|
switch d := dest.(type) {
|
|
case *[]uint64:
|
|
tmp := make([]uint64, len(values))
|
|
for i, v := range values {
|
|
b.uint(sourceParam, v, &tmp[i], 64)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]uint32:
|
|
tmp := make([]uint32, len(values))
|
|
for i, v := range values {
|
|
b.uint(sourceParam, v, &tmp[i], 32)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]uint16:
|
|
tmp := make([]uint16, len(values))
|
|
for i, v := range values {
|
|
b.uint(sourceParam, v, &tmp[i], 16)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]uint8: // byte is alias to uint8
|
|
tmp := make([]uint8, len(values))
|
|
for i, v := range values {
|
|
b.uint(sourceParam, v, &tmp[i], 8)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]uint:
|
|
tmp := make([]uint, len(values))
|
|
for i, v := range values {
|
|
b.uint(sourceParam, v, &tmp[i], 0)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Uint64s binds parameter to slice of uint64
|
|
func (b *ValueBinder) Uint64s(sourceParam string, dest *[]uint64) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustUint64s requires parameter value to exist to bind to uint64 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint64s(sourceParam string, dest *[]uint64) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Uint32s binds parameter to slice of uint32
|
|
func (b *ValueBinder) Uint32s(sourceParam string, dest *[]uint32) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustUint32s requires parameter value to exist to bind to uint32 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint32s(sourceParam string, dest *[]uint32) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Uint16s binds parameter to slice of uint16
|
|
func (b *ValueBinder) Uint16s(sourceParam string, dest *[]uint16) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustUint16s requires parameter value to exist to bind to uint16 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint16s(sourceParam string, dest *[]uint16) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Uint8s binds parameter to slice of uint8
|
|
func (b *ValueBinder) Uint8s(sourceParam string, dest *[]uint8) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustUint8s requires parameter value to exist to bind to uint8 slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUint8s(sourceParam string, dest *[]uint8) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Uints binds parameter to slice of uint
|
|
func (b *ValueBinder) Uints(sourceParam string, dest *[]uint) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustUints requires parameter value to exist to bind to uint slice variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustUints(sourceParam string, dest *[]uint) *ValueBinder {
|
|
return b.uintsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Bool binds parameter to bool variable
|
|
func (b *ValueBinder) Bool(sourceParam string, dest *bool) *ValueBinder {
|
|
return b.boolValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustBool requires parameter value to exist to bind to bool variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustBool(sourceParam string, dest *bool) *ValueBinder {
|
|
return b.boolValue(sourceParam, dest, true)
|
|
}
|
|
|
|
func (b *ValueBinder) boolValue(sourceParam string, dest *bool, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
return b.bool(sourceParam, value, dest)
|
|
}
|
|
|
|
func (b *ValueBinder) bool(sourceParam string, value string, dest *bool) *ValueBinder {
|
|
n, err := strconv.ParseBool(value)
|
|
if err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to bool", err))
|
|
return b
|
|
}
|
|
|
|
*dest = n
|
|
return b
|
|
}
|
|
|
|
func (b *ValueBinder) boolsValue(sourceParam string, dest *[]bool, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
return b.bools(sourceParam, values, dest)
|
|
}
|
|
|
|
func (b *ValueBinder) bools(sourceParam string, values []string, dest *[]bool) *ValueBinder {
|
|
tmp := make([]bool, len(values))
|
|
for i, v := range values {
|
|
b.bool(sourceParam, v, &tmp[i])
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*dest = tmp
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Bools binds parameter values to slice of bool variables
|
|
func (b *ValueBinder) Bools(sourceParam string, dest *[]bool) *ValueBinder {
|
|
return b.boolsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustBools requires parameter values to exist to bind to slice of bool variables. Returns error when values does not exist
|
|
func (b *ValueBinder) MustBools(sourceParam string, dest *[]bool) *ValueBinder {
|
|
return b.boolsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Float64 binds parameter to float64 variable
|
|
func (b *ValueBinder) Float64(sourceParam string, dest *float64) *ValueBinder {
|
|
return b.floatValue(sourceParam, dest, 64, false)
|
|
}
|
|
|
|
// MustFloat64 requires parameter value to exist to bind to float64 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustFloat64(sourceParam string, dest *float64) *ValueBinder {
|
|
return b.floatValue(sourceParam, dest, 64, true)
|
|
}
|
|
|
|
// Float32 binds parameter to float32 variable
|
|
func (b *ValueBinder) Float32(sourceParam string, dest *float32) *ValueBinder {
|
|
return b.floatValue(sourceParam, dest, 32, false)
|
|
}
|
|
|
|
// MustFloat32 requires parameter value to exist to bind to float32 variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustFloat32(sourceParam string, dest *float32) *ValueBinder {
|
|
return b.floatValue(sourceParam, dest, 32, true)
|
|
}
|
|
|
|
func (b *ValueBinder) floatValue(sourceParam string, dest interface{}, bitSize int, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
|
|
return b.float(sourceParam, value, dest, bitSize)
|
|
}
|
|
|
|
func (b *ValueBinder) float(sourceParam string, value string, dest interface{}, bitSize int) *ValueBinder {
|
|
n, err := strconv.ParseFloat(value, bitSize)
|
|
if err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, fmt.Sprintf("failed to bind field value to float%v", bitSize), err))
|
|
return b
|
|
}
|
|
|
|
switch d := dest.(type) {
|
|
case *float64:
|
|
*d = n
|
|
case *float32:
|
|
*d = float32(n)
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (b *ValueBinder) floatsValue(sourceParam string, dest interface{}, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
return b.floats(sourceParam, values, dest)
|
|
}
|
|
|
|
func (b *ValueBinder) floats(sourceParam string, values []string, dest interface{}) *ValueBinder {
|
|
switch d := dest.(type) {
|
|
case *[]float64:
|
|
tmp := make([]float64, len(values))
|
|
for i, v := range values {
|
|
b.float(sourceParam, v, &tmp[i], 64)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
case *[]float32:
|
|
tmp := make([]float32, len(values))
|
|
for i, v := range values {
|
|
b.float(sourceParam, v, &tmp[i], 32)
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
}
|
|
if b.errors == nil {
|
|
*d = tmp
|
|
}
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Float64s binds parameter values to slice of float64 variables
|
|
func (b *ValueBinder) Float64s(sourceParam string, dest *[]float64) *ValueBinder {
|
|
return b.floatsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustFloat64s requires parameter values to exist to bind to slice of float64 variables. Returns error when values does not exist
|
|
func (b *ValueBinder) MustFloat64s(sourceParam string, dest *[]float64) *ValueBinder {
|
|
return b.floatsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Float32s binds parameter values to slice of float32 variables
|
|
func (b *ValueBinder) Float32s(sourceParam string, dest *[]float32) *ValueBinder {
|
|
return b.floatsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustFloat32s requires parameter values to exist to bind to slice of float32 variables. Returns error when values does not exist
|
|
func (b *ValueBinder) MustFloat32s(sourceParam string, dest *[]float32) *ValueBinder {
|
|
return b.floatsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
// Time binds parameter to time.Time variable
|
|
func (b *ValueBinder) Time(sourceParam string, dest *time.Time, layout string) *ValueBinder {
|
|
return b.time(sourceParam, dest, layout, false)
|
|
}
|
|
|
|
// MustTime requires parameter value to exist to bind to time.Time variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustTime(sourceParam string, dest *time.Time, layout string) *ValueBinder {
|
|
return b.time(sourceParam, dest, layout, true)
|
|
}
|
|
|
|
func (b *ValueBinder) time(sourceParam string, dest *time.Time, layout string, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
t, err := time.Parse(layout, value)
|
|
if err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to Time", err))
|
|
return b
|
|
}
|
|
*dest = t
|
|
return b
|
|
}
|
|
|
|
// Times binds parameter values to slice of time.Time variables
|
|
func (b *ValueBinder) Times(sourceParam string, dest *[]time.Time, layout string) *ValueBinder {
|
|
return b.times(sourceParam, dest, layout, false)
|
|
}
|
|
|
|
// MustTimes requires parameter values to exist to bind to slice of time.Time variables. Returns error when values does not exist
|
|
func (b *ValueBinder) MustTimes(sourceParam string, dest *[]time.Time, layout string) *ValueBinder {
|
|
return b.times(sourceParam, dest, layout, true)
|
|
}
|
|
|
|
func (b *ValueBinder) times(sourceParam string, dest *[]time.Time, layout string, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
|
|
tmp := make([]time.Time, len(values))
|
|
for i, v := range values {
|
|
t, err := time.Parse(layout, v)
|
|
if err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{v}, "failed to bind field value to Time", err))
|
|
if b.failFast {
|
|
return b
|
|
}
|
|
continue
|
|
}
|
|
tmp[i] = t
|
|
}
|
|
if b.errors == nil {
|
|
*dest = tmp
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Duration binds parameter to time.Duration variable
|
|
func (b *ValueBinder) Duration(sourceParam string, dest *time.Duration) *ValueBinder {
|
|
return b.duration(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustDuration requires parameter value to exist to bind to time.Duration variable. Returns error when value does not exist
|
|
func (b *ValueBinder) MustDuration(sourceParam string, dest *time.Duration) *ValueBinder {
|
|
return b.duration(sourceParam, dest, true)
|
|
}
|
|
|
|
func (b *ValueBinder) duration(sourceParam string, dest *time.Duration, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
t, err := time.ParseDuration(value)
|
|
if err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to Duration", err))
|
|
return b
|
|
}
|
|
*dest = t
|
|
return b
|
|
}
|
|
|
|
// Durations binds parameter values to slice of time.Duration variables
|
|
func (b *ValueBinder) Durations(sourceParam string, dest *[]time.Duration) *ValueBinder {
|
|
return b.durationsValue(sourceParam, dest, false)
|
|
}
|
|
|
|
// MustDurations requires parameter values to exist to bind to slice of time.Duration variables. Returns error when values does not exist
|
|
func (b *ValueBinder) MustDurations(sourceParam string, dest *[]time.Duration) *ValueBinder {
|
|
return b.durationsValue(sourceParam, dest, true)
|
|
}
|
|
|
|
func (b *ValueBinder) durationsValue(sourceParam string, dest *[]time.Duration, valueMustExist bool) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
values := b.ValuesFunc(sourceParam)
|
|
if len(values) == 0 {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
return b.durations(sourceParam, values, dest)
|
|
}
|
|
|
|
func (b *ValueBinder) durations(sourceParam string, values []string, dest *[]time.Duration) *ValueBinder {
|
|
tmp := make([]time.Duration, len(values))
|
|
for i, v := range values {
|
|
t, err := time.ParseDuration(v)
|
|
if err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{v}, "failed to bind field value to Duration", err))
|
|
if b.failFast {
|
|
return b
|
|
}
|
|
continue
|
|
}
|
|
tmp[i] = t
|
|
}
|
|
if b.errors == nil {
|
|
*dest = tmp
|
|
}
|
|
return b
|
|
}
|
|
|
|
// UnixTime binds parameter to time.Time variable (in local Time corresponding to the given Unix time).
|
|
//
|
|
// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
|
|
//
|
|
// Note:
|
|
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
|
func (b *ValueBinder) UnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
|
return b.unixTime(sourceParam, dest, false, time.Second)
|
|
}
|
|
|
|
// MustUnixTime requires parameter value to exist to bind to time.Duration variable (in local time corresponding
|
|
// to the given Unix time). Returns error when value does not exist.
|
|
//
|
|
// Example: 1609180603 bind to 2020-12-28T18:36:43.000000000+00:00
|
|
//
|
|
// Note:
|
|
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
|
func (b *ValueBinder) MustUnixTime(sourceParam string, dest *time.Time) *ValueBinder {
|
|
return b.unixTime(sourceParam, dest, true, time.Second)
|
|
}
|
|
|
|
// UnixTimeMilli binds parameter to time.Time variable (in local time corresponding to the given Unix time in millisecond precision).
|
|
//
|
|
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
|
//
|
|
// Note:
|
|
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
|
func (b *ValueBinder) UnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
|
return b.unixTime(sourceParam, dest, false, time.Millisecond)
|
|
}
|
|
|
|
// MustUnixTimeMilli requires parameter value to exist to bind to time.Duration variable (in local time corresponding
|
|
// to the given Unix time in millisecond precision). Returns error when value does not exist.
|
|
//
|
|
// Example: 1647184410140 bind to 2022-03-13T15:13:30.140000000+00:00
|
|
//
|
|
// Note:
|
|
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
|
func (b *ValueBinder) MustUnixTimeMilli(sourceParam string, dest *time.Time) *ValueBinder {
|
|
return b.unixTime(sourceParam, dest, true, time.Millisecond)
|
|
}
|
|
|
|
// UnixTimeNano binds parameter to time.Time variable (in local time corresponding to the given Unix time in nanosecond precision).
|
|
//
|
|
// Example: 1609180603123456789 binds to 2020-12-28T18:36:43.123456789+00:00
|
|
// Example: 1000000000 binds to 1970-01-01T00:00:01.000000000+00:00
|
|
// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
|
|
//
|
|
// Note:
|
|
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
|
// - Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
|
func (b *ValueBinder) UnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
|
return b.unixTime(sourceParam, dest, false, time.Nanosecond)
|
|
}
|
|
|
|
// MustUnixTimeNano requires parameter value to exist to bind to time.Duration variable (in local Time corresponding
|
|
// to the given Unix time value in nano second precision). Returns error when value does not exist.
|
|
//
|
|
// Example: 1609180603123456789 binds to 2020-12-28T18:36:43.123456789+00:00
|
|
// Example: 1000000000 binds to 1970-01-01T00:00:01.000000000+00:00
|
|
// Example: 999999999 binds to 1970-01-01T00:00:00.999999999+00:00
|
|
//
|
|
// Note:
|
|
// - time.Time{} (param is empty) and time.Unix(0,0) (param = "0") are not equal
|
|
// - Javascript's Number type only has about 53 bits of precision (Number.MAX_SAFE_INTEGER = 9007199254740991). Compare it to 1609180603123456789 in example.
|
|
func (b *ValueBinder) MustUnixTimeNano(sourceParam string, dest *time.Time) *ValueBinder {
|
|
return b.unixTime(sourceParam, dest, true, time.Nanosecond)
|
|
}
|
|
|
|
func (b *ValueBinder) unixTime(sourceParam string, dest *time.Time, valueMustExist bool, precision time.Duration) *ValueBinder {
|
|
if b.failFast && b.errors != nil {
|
|
return b
|
|
}
|
|
|
|
value := b.ValueFunc(sourceParam)
|
|
if value == "" {
|
|
if valueMustExist {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "required field value is empty", nil))
|
|
}
|
|
return b
|
|
}
|
|
|
|
n, err := strconv.ParseInt(value, 10, 64)
|
|
if err != nil {
|
|
b.setError(b.ErrorFunc(sourceParam, []string{value}, "failed to bind field value to Time", err))
|
|
return b
|
|
}
|
|
|
|
switch precision {
|
|
case time.Second:
|
|
*dest = time.Unix(n, 0)
|
|
case time.Millisecond:
|
|
*dest = time.Unix(n/1e3, (n%1e3)*1e6) // TODO: time.UnixMilli(n) exists since Go1.17 switch to that when min version allows
|
|
case time.Nanosecond:
|
|
*dest = time.Unix(0, n)
|
|
}
|
|
return b
|
|
}
|