Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
78e1c33e30
|
|||
d2f2a0558a
|
|||
fc4bed4b9f
|
|||
![]() |
94a7bf250d | ||
f6121a6961
|
|||
7fc73f1e93
|
|||
2504ef00a0
|
|||
fc5803493c | |||
a9295bfabf | |||
12fa53d848
|
|||
d2bb362135
|
@@ -1,14 +1,15 @@
|
|||||||
package cursortoken
|
package cursortoken
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RawFilter interface {
|
type RawFilter interface {
|
||||||
FilterQuery() mongo.Pipeline
|
FilterQuery(ctx context.Context) mongo.Pipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
type Filter interface {
|
type Filter interface {
|
||||||
FilterQuery() mongo.Pipeline
|
FilterQuery(ctx context.Context) mongo.Pipeline
|
||||||
Pagination() (string, SortDirection, string, SortDirection)
|
Pagination(ctx context.Context) (string, SortDirection, string, SortDirection)
|
||||||
}
|
}
|
||||||
|
@@ -55,18 +55,6 @@ import (
|
|||||||
// => Wrap/New + Fatal
|
// => Wrap/New + Fatal
|
||||||
//
|
//
|
||||||
|
|
||||||
var stackSkipLogger zerolog.Logger
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cw := zerolog.ConsoleWriter{
|
|
||||||
Out: os.Stdout,
|
|
||||||
TimeFormat: "2006-01-02 15:04:05 Z07:00",
|
|
||||||
}
|
|
||||||
|
|
||||||
multi := zerolog.MultiLevelWriter(cw)
|
|
||||||
stackSkipLogger = zerolog.New(multi).With().Timestamp().CallerWithSkipFrameCount(4).Logger()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Builder struct {
|
type Builder struct {
|
||||||
wrappedErr error
|
wrappedErr error
|
||||||
errorData *ExErr
|
errorData *ExErr
|
||||||
@@ -435,9 +423,9 @@ func (b *Builder) Build(ctxs ...context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pkgconfig.ZeroLogErrTraces && !b.noLog && (b.errorData.Severity == SevErr || b.errorData.Severity == SevFatal) {
|
if pkgconfig.ZeroLogErrTraces && !b.noLog && (b.errorData.Severity == SevErr || b.errorData.Severity == SevFatal) {
|
||||||
b.errorData.ShortLog(stackSkipLogger.Error())
|
b.errorData.ShortLog(pkgconfig.ZeroLogger.Error())
|
||||||
} else if pkgconfig.ZeroLogAllTraces && !b.noLog {
|
} else if pkgconfig.ZeroLogAllTraces && !b.noLog {
|
||||||
b.errorData.ShortLog(stackSkipLogger.Error())
|
b.errorData.ShortLog(pkgconfig.ZeroLogger.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
b.errorData.CallListener(MethodBuild)
|
b.errorData.CallListener(MethodBuild)
|
||||||
@@ -459,9 +447,9 @@ func (b *Builder) Output(ctx context.Context, g *gin.Context) {
|
|||||||
b.errorData.Output(g)
|
b.errorData.Output(g)
|
||||||
|
|
||||||
if (b.errorData.Severity == SevErr || b.errorData.Severity == SevFatal) && (pkgconfig.ZeroLogErrGinOutput || pkgconfig.ZeroLogAllGinOutput) {
|
if (b.errorData.Severity == SevErr || b.errorData.Severity == SevFatal) && (pkgconfig.ZeroLogErrGinOutput || pkgconfig.ZeroLogAllGinOutput) {
|
||||||
b.errorData.Log(stackSkipLogger.Error())
|
b.errorData.Log(pkgconfig.ZeroLogger.Error())
|
||||||
} else if (b.errorData.Severity == SevWarn) && (pkgconfig.ZeroLogAllGinOutput) {
|
} else if (b.errorData.Severity == SevWarn) && (pkgconfig.ZeroLogAllGinOutput) {
|
||||||
b.errorData.Log(stackSkipLogger.Warn())
|
b.errorData.Log(pkgconfig.ZeroLogger.Warn())
|
||||||
}
|
}
|
||||||
|
|
||||||
b.errorData.CallListener(MethodOutput)
|
b.errorData.CallListener(MethodOutput)
|
||||||
@@ -477,9 +465,9 @@ func (b *Builder) Print(ctxs ...context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if b.errorData.Severity == SevErr || b.errorData.Severity == SevFatal {
|
if b.errorData.Severity == SevErr || b.errorData.Severity == SevFatal {
|
||||||
b.errorData.Log(stackSkipLogger.Error())
|
b.errorData.Log(pkgconfig.ZeroLogger.Error())
|
||||||
} else if b.errorData.Severity == SevWarn {
|
} else if b.errorData.Severity == SevWarn {
|
||||||
b.errorData.ShortLog(stackSkipLogger.Warn())
|
b.errorData.ShortLog(pkgconfig.ZeroLogger.Warn())
|
||||||
}
|
}
|
||||||
|
|
||||||
b.errorData.CallListener(MethodPrint)
|
b.errorData.CallListener(MethodPrint)
|
||||||
@@ -493,12 +481,13 @@ func (b *Builder) Format(level LogPrintLevel) string {
|
|||||||
// If the error is SevErr we also send it to the error-service
|
// If the error is SevErr we also send it to the error-service
|
||||||
func (b *Builder) Fatal(ctxs ...context.Context) {
|
func (b *Builder) Fatal(ctxs ...context.Context) {
|
||||||
|
|
||||||
|
b.errorData.Severity = SevFatal
|
||||||
|
|
||||||
for _, dctx := range ctxs {
|
for _, dctx := range ctxs {
|
||||||
b.CtxData(MethodFatal, dctx)
|
b.CtxData(MethodFatal, dctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.errorData.Severity = SevFatal
|
b.errorData.Log(pkgconfig.ZeroLogger.WithLevel(zerolog.FatalLevel))
|
||||||
b.errorData.Log(stackSkipLogger.WithLevel(zerolog.FatalLevel))
|
|
||||||
|
|
||||||
b.errorData.CallListener(MethodFatal)
|
b.errorData.CallListener(MethodFatal)
|
||||||
|
|
||||||
|
@@ -56,7 +56,7 @@ func wrapExErr(e *ExErr, msg string, cat ErrorCategory, stacktraceskip int) *ExE
|
|||||||
UniqueID: newID(),
|
UniqueID: newID(),
|
||||||
Category: cat,
|
Category: cat,
|
||||||
Type: TypeWrap,
|
Type: TypeWrap,
|
||||||
Severity: SevErr,
|
Severity: e.Severity,
|
||||||
Timestamp: time.Now(),
|
Timestamp: time.Now(),
|
||||||
StatusCode: e.StatusCode,
|
StatusCode: e.StatusCode,
|
||||||
Message: msg,
|
Message: msg,
|
||||||
|
@@ -4,8 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrorPackageConfig struct {
|
type ErrorPackageConfig struct {
|
||||||
@@ -21,6 +23,7 @@ type ErrorPackageConfig struct {
|
|||||||
ZeroLogAllGinOutput bool // autom print zerolog logs on ginext.Error() / .Output(gin) (for all Severities)
|
ZeroLogAllGinOutput bool // autom print zerolog logs on ginext.Error() / .Output(gin) (for all Severities)
|
||||||
ExtendGinMeta func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request) // (Optionally) extend the final error meta values with additional data from the gin context (a few are automatically added, here more can be included)
|
ExtendGinMeta func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request) // (Optionally) extend the final error meta values with additional data from the gin context (a few are automatically added, here more can be included)
|
||||||
ExtendContextMeta func(b *Builder, method Method, dctx context.Context) // (Optionally) extend the final error meta values with additional data from the context (a few are automatically added, here more can be included)
|
ExtendContextMeta func(b *Builder, method Method, dctx context.Context) // (Optionally) extend the final error meta values with additional data from the context (a few are automatically added, here more can be included)
|
||||||
|
ZeroLogger zerolog.Logger // The logger used to print exerr log messages
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrorPackageConfigInit struct {
|
type ErrorPackageConfigInit struct {
|
||||||
@@ -36,6 +39,7 @@ type ErrorPackageConfigInit struct {
|
|||||||
ZeroLogAllGinOutput *bool
|
ZeroLogAllGinOutput *bool
|
||||||
ExtendGinMeta func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request)
|
ExtendGinMeta func(ctx context.Context, b *Builder, g *gin.Context, req *http.Request)
|
||||||
ExtendContextMeta func(b *Builder, method Method, dctx context.Context)
|
ExtendContextMeta func(b *Builder, method Method, dctx context.Context)
|
||||||
|
ZeroLogger *zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
var initialized = false
|
var initialized = false
|
||||||
@@ -81,6 +85,13 @@ func Init(cfg ErrorPackageConfigInit) {
|
|||||||
egcm = cfg.ExtendContextMeta
|
egcm = cfg.ExtendContextMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var logger zerolog.Logger
|
||||||
|
if cfg.ZeroLogger != nil {
|
||||||
|
logger = *cfg.ZeroLogger
|
||||||
|
} else {
|
||||||
|
logger = newDefaultLogger()
|
||||||
|
}
|
||||||
|
|
||||||
pkgconfig = ErrorPackageConfig{
|
pkgconfig = ErrorPackageConfig{
|
||||||
ZeroLogErrTraces: langext.Coalesce(cfg.ZeroLogErrTraces, pkgconfig.ZeroLogErrTraces),
|
ZeroLogErrTraces: langext.Coalesce(cfg.ZeroLogErrTraces, pkgconfig.ZeroLogErrTraces),
|
||||||
ZeroLogAllTraces: langext.Coalesce(cfg.ZeroLogAllTraces, pkgconfig.ZeroLogAllTraces),
|
ZeroLogAllTraces: langext.Coalesce(cfg.ZeroLogAllTraces, pkgconfig.ZeroLogAllTraces),
|
||||||
@@ -94,11 +105,23 @@ func Init(cfg ErrorPackageConfigInit) {
|
|||||||
ZeroLogErrGinOutput: langext.Coalesce(cfg.ZeroLogErrGinOutput, pkgconfig.ZeroLogErrGinOutput),
|
ZeroLogErrGinOutput: langext.Coalesce(cfg.ZeroLogErrGinOutput, pkgconfig.ZeroLogErrGinOutput),
|
||||||
ExtendGinMeta: egm,
|
ExtendGinMeta: egm,
|
||||||
ExtendContextMeta: egcm,
|
ExtendContextMeta: egcm,
|
||||||
|
ZeroLogger: logger,
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true
|
initialized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDefaultLogger() zerolog.Logger {
|
||||||
|
cw := zerolog.ConsoleWriter{
|
||||||
|
Out: os.Stdout,
|
||||||
|
TimeFormat: "2006-01-02 15:04:05 Z07:00",
|
||||||
|
}
|
||||||
|
|
||||||
|
multi := zerolog.MultiLevelWriter(cw)
|
||||||
|
|
||||||
|
return zerolog.New(multi).With().Timestamp().CallerWithSkipFrameCount(4).Logger()
|
||||||
|
}
|
||||||
|
|
||||||
func Initialized() bool {
|
func Initialized() bool {
|
||||||
return initialized
|
return initialized
|
||||||
}
|
}
|
||||||
|
@@ -51,6 +51,20 @@ type Options struct {
|
|||||||
|
|
||||||
// NewEngine creates a new (wrapped) ginEngine
|
// NewEngine creates a new (wrapped) ginEngine
|
||||||
func NewEngine(opt Options) *GinWrapper {
|
func NewEngine(opt Options) *GinWrapper {
|
||||||
|
ginDebug := langext.Coalesce(opt.GinDebug, true)
|
||||||
|
if ginDebug {
|
||||||
|
gin.SetMode(gin.DebugMode)
|
||||||
|
|
||||||
|
// do not debug-print routes
|
||||||
|
gin.DebugPrintRouteFunc = func(_, _, _ string, _ int) {}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
gin.SetMode(gin.ReleaseMode)
|
||||||
|
|
||||||
|
// do not debug-print routes
|
||||||
|
gin.DebugPrintRouteFunc = func(_, _, _ string, _ int) {}
|
||||||
|
}
|
||||||
|
|
||||||
engine := gin.New()
|
engine := gin.New()
|
||||||
|
|
||||||
wrapper := &GinWrapper{
|
wrapper := &GinWrapper{
|
||||||
@@ -58,7 +72,7 @@ func NewEngine(opt Options) *GinWrapper {
|
|||||||
opt: opt,
|
opt: opt,
|
||||||
suppressGinLogs: langext.Coalesce(opt.SuppressGinLogs, false),
|
suppressGinLogs: langext.Coalesce(opt.SuppressGinLogs, false),
|
||||||
allowCors: langext.Coalesce(opt.AllowCors, false),
|
allowCors: langext.Coalesce(opt.AllowCors, false),
|
||||||
ginDebug: langext.Coalesce(opt.GinDebug, true),
|
ginDebug: ginDebug,
|
||||||
bufferBody: langext.Coalesce(opt.BufferBody, false),
|
bufferBody: langext.Coalesce(opt.BufferBody, false),
|
||||||
requestTimeout: langext.Coalesce(opt.Timeout, 24*time.Hour),
|
requestTimeout: langext.Coalesce(opt.Timeout, 24*time.Hour),
|
||||||
listenerBeforeRequest: opt.ListenerBeforeRequest,
|
listenerBeforeRequest: opt.ListenerBeforeRequest,
|
||||||
@@ -72,24 +86,10 @@ func NewEngine(opt Options) *GinWrapper {
|
|||||||
engine.Use(CorsMiddleware())
|
engine.Use(CorsMiddleware())
|
||||||
}
|
}
|
||||||
|
|
||||||
if wrapper.ginDebug {
|
if ginDebug && !wrapper.suppressGinLogs {
|
||||||
gin.SetMode(gin.DebugMode)
|
ginlogger := gin.Logger()
|
||||||
|
engine.Use(func(context *gin.Context) { ginlogger(context) })
|
||||||
// do not debug-print routes
|
|
||||||
gin.DebugPrintRouteFunc = func(_, _, _ string, _ int) {}
|
|
||||||
|
|
||||||
if !wrapper.suppressGinLogs {
|
|
||||||
ginlogger := gin.Logger()
|
|
||||||
engine.Use(func(context *gin.Context) { ginlogger(context) })
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
gin.SetMode(gin.ReleaseMode)
|
|
||||||
|
|
||||||
// do not debug-print routes
|
|
||||||
gin.DebugPrintRouteFunc = func(_, _, _ string, _ int) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,13 +1,8 @@
|
|||||||
package ginext
|
package ginext
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
||||||
json "gogs.mikescher.com/BlackForestBytes/goext/gojson"
|
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type cookieval struct {
|
type cookieval struct {
|
||||||
@@ -41,464 +36,6 @@ type InspectableHTTPResponse interface {
|
|||||||
Headers() []string
|
Headers() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type jsonHTTPResponse struct {
|
|
||||||
statusCode int
|
|
||||||
data any
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) jsonRenderer(g *gin.Context) json.GoJsonRender {
|
|
||||||
var f *string
|
|
||||||
if jsonfilter := g.GetString("goext.jsonfilter"); jsonfilter != "" {
|
|
||||||
f = &jsonfilter
|
|
||||||
}
|
|
||||||
return json.GoJsonRender{Data: j.data, NilSafeSlices: true, NilSafeMaps: true, Filter: f}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) Write(g *gin.Context) {
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
g.Render(j.statusCode, j.jsonRenderer(g))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) IsSuccess() bool {
|
|
||||||
return j.statusCode >= 200 && j.statusCode <= 399
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) Statuscode() int {
|
|
||||||
return j.statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) BodyString(g *gin.Context) *string {
|
|
||||||
if str, err := j.jsonRenderer(g).RenderString(); err == nil {
|
|
||||||
return &str
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) ContentType() string {
|
|
||||||
return "application/json"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonHTTPResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
type emptyHTTPResponse struct {
|
|
||||||
statusCode int
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) Write(g *gin.Context) {
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
g.Status(j.statusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) IsSuccess() bool {
|
|
||||||
return j.statusCode >= 200 && j.statusCode <= 399
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) Statuscode() int {
|
|
||||||
return j.statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) BodyString(*gin.Context) *string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) ContentType() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j emptyHTTPResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
type textHTTPResponse struct {
|
|
||||||
statusCode int
|
|
||||||
data string
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) Write(g *gin.Context) {
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
g.String(j.statusCode, "%s", j.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) IsSuccess() bool {
|
|
||||||
return j.statusCode >= 200 && j.statusCode <= 399
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) Statuscode() int {
|
|
||||||
return j.statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) BodyString(*gin.Context) *string {
|
|
||||||
return langext.Ptr(j.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) ContentType() string {
|
|
||||||
return "text/plain"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j textHTTPResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
type dataHTTPResponse struct {
|
|
||||||
statusCode int
|
|
||||||
data []byte
|
|
||||||
contentType string
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) Write(g *gin.Context) {
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
g.Data(j.statusCode, j.contentType, j.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) IsSuccess() bool {
|
|
||||||
return j.statusCode >= 200 && j.statusCode <= 399
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) Statuscode() int {
|
|
||||||
return j.statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) BodyString(*gin.Context) *string {
|
|
||||||
return langext.Ptr(string(j.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) ContentType() string {
|
|
||||||
return j.contentType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j dataHTTPResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
type fileHTTPResponse struct {
|
|
||||||
mimetype string
|
|
||||||
filepath string
|
|
||||||
filename *string
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) Write(g *gin.Context) {
|
|
||||||
g.Header("Content-Type", j.mimetype) // if we don't set it here gin does weird file-sniffing later...
|
|
||||||
if j.filename != nil {
|
|
||||||
g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename))
|
|
||||||
|
|
||||||
}
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
g.File(j.filepath)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) IsSuccess() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) Statuscode() int {
|
|
||||||
return 200
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) BodyString(*gin.Context) *string {
|
|
||||||
data, err := os.ReadFile(j.filepath)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return langext.Ptr(string(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) ContentType() string {
|
|
||||||
return j.mimetype
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j fileHTTPResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
type downloadDataHTTPResponse struct {
|
|
||||||
statusCode int
|
|
||||||
mimetype string
|
|
||||||
data []byte
|
|
||||||
filename *string
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) Write(g *gin.Context) {
|
|
||||||
g.Header("Content-Type", j.mimetype) // if we don't set it here gin does weird file-sniffing later...
|
|
||||||
if j.filename != nil {
|
|
||||||
g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename))
|
|
||||||
}
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
g.Data(j.statusCode, j.mimetype, j.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) IsSuccess() bool {
|
|
||||||
return j.statusCode >= 200 && j.statusCode <= 399
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) Statuscode() int {
|
|
||||||
return j.statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) BodyString(*gin.Context) *string {
|
|
||||||
return langext.Ptr(string(j.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) ContentType() string {
|
|
||||||
return j.mimetype
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j downloadDataHTTPResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
type redirectHTTPResponse struct {
|
|
||||||
statusCode int
|
|
||||||
url string
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) Write(g *gin.Context) {
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
g.Redirect(j.statusCode, j.url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) IsSuccess() bool {
|
|
||||||
return j.statusCode >= 200 && j.statusCode <= 399
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) Statuscode() int {
|
|
||||||
return j.statusCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) BodyString(*gin.Context) *string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) ContentType() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j redirectHTTPResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
type jsonAPIErrResponse struct {
|
|
||||||
err *exerr.ExErr
|
|
||||||
headers []headerval
|
|
||||||
cookies []cookieval
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) Write(g *gin.Context) {
|
|
||||||
for _, v := range j.headers {
|
|
||||||
g.Header(v.Key, v.Val)
|
|
||||||
}
|
|
||||||
for _, v := range j.cookies {
|
|
||||||
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
|
||||||
}
|
|
||||||
|
|
||||||
exerr.Get(j.err).Output(context.Background(), g)
|
|
||||||
|
|
||||||
j.err.CallListener(exerr.MethodOutput)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) WithHeader(k string, v string) HTTPResponse {
|
|
||||||
j.headers = append(j.headers, headerval{k, v})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
|
||||||
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
|
||||||
return j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) IsSuccess() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) Statuscode() int {
|
|
||||||
return langext.Coalesce(j.err.RecursiveStatuscode(), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) BodyString(*gin.Context) *string {
|
|
||||||
if str, err := j.err.ToDefaultAPIJson(); err == nil {
|
|
||||||
return &str
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) ContentType() string {
|
|
||||||
return "application/json"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) Headers() []string {
|
|
||||||
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j jsonAPIErrResponse) Unwrap() error {
|
|
||||||
return j.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func Status(sc int) HTTPResponse {
|
|
||||||
return &emptyHTTPResponse{statusCode: sc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func JSON(sc int, data any) HTTPResponse {
|
|
||||||
return &jsonHTTPResponse{statusCode: sc, data: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Data(sc int, contentType string, data []byte) HTTPResponse {
|
|
||||||
return &dataHTTPResponse{statusCode: sc, contentType: contentType, data: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Text(sc int, data string) HTTPResponse {
|
|
||||||
return &textHTTPResponse{statusCode: sc, data: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
func File(mimetype string, filepath string) HTTPResponse {
|
|
||||||
return &fileHTTPResponse{mimetype: mimetype, filepath: filepath}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Download(mimetype string, filepath string, filename string) HTTPResponse {
|
|
||||||
return &fileHTTPResponse{mimetype: mimetype, filepath: filepath, filename: &filename}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DownloadData(status int, mimetype string, filename string, data []byte) HTTPResponse {
|
|
||||||
return &downloadDataHTTPResponse{statusCode: status, mimetype: mimetype, data: data, filename: &filename}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Redirect(sc int, newURL string) HTTPResponse {
|
|
||||||
return &redirectHTTPResponse{statusCode: sc, url: newURL}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Error(e error) HTTPResponse {
|
|
||||||
return &jsonAPIErrResponse{
|
|
||||||
err: exerr.FromError(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ErrWrap(e error, errorType exerr.ErrorType, msg string) HTTPResponse {
|
|
||||||
return &jsonAPIErrResponse{
|
|
||||||
err: exerr.FromError(exerr.Wrap(e, msg).WithType(errorType).Build()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NotImplemented() HTTPResponse {
|
func NotImplemented() HTTPResponse {
|
||||||
return Error(exerr.New(exerr.TypeNotImplemented, "").Build())
|
return Error(exerr.New(exerr.TypeNotImplemented, "").Build())
|
||||||
}
|
}
|
||||||
|
58
ginext/responseData.go
Normal file
58
ginext/responseData.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dataHTTPResponse struct {
|
||||||
|
statusCode int
|
||||||
|
data []byte
|
||||||
|
contentType string
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) Write(g *gin.Context) {
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
g.Data(j.statusCode, j.contentType, j.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) IsSuccess() bool {
|
||||||
|
return j.statusCode >= 200 && j.statusCode <= 399
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) Statuscode() int {
|
||||||
|
return j.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) BodyString(*gin.Context) *string {
|
||||||
|
return langext.Ptr(string(j.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) ContentType() string {
|
||||||
|
return j.contentType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j dataHTTPResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func Data(sc int, contentType string, data []byte) HTTPResponse {
|
||||||
|
return &dataHTTPResponse{statusCode: sc, contentType: contentType, data: data}
|
||||||
|
}
|
64
ginext/responseDownload.go
Normal file
64
ginext/responseDownload.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type downloadDataHTTPResponse struct {
|
||||||
|
statusCode int
|
||||||
|
mimetype string
|
||||||
|
data []byte
|
||||||
|
filename *string
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) Write(g *gin.Context) {
|
||||||
|
g.Header("Content-Type", j.mimetype) // if we don't set it here gin does weird file-sniffing later...
|
||||||
|
if j.filename != nil {
|
||||||
|
g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename))
|
||||||
|
}
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
g.Data(j.statusCode, j.mimetype, j.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) IsSuccess() bool {
|
||||||
|
return j.statusCode >= 200 && j.statusCode <= 399
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) Statuscode() int {
|
||||||
|
return j.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) BodyString(*gin.Context) *string {
|
||||||
|
return langext.Ptr(string(j.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) ContentType() string {
|
||||||
|
return j.mimetype
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j downloadDataHTTPResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadData(status int, mimetype string, filename string, data []byte) HTTPResponse {
|
||||||
|
return &downloadDataHTTPResponse{statusCode: status, mimetype: mimetype, data: data, filename: &filename}
|
||||||
|
}
|
56
ginext/responseEmpty.go
Normal file
56
ginext/responseEmpty.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type emptyHTTPResponse struct {
|
||||||
|
statusCode int
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) Write(g *gin.Context) {
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
g.Status(j.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) IsSuccess() bool {
|
||||||
|
return j.statusCode >= 200 && j.statusCode <= 399
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) Statuscode() int {
|
||||||
|
return j.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) BodyString(*gin.Context) *string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) ContentType() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j emptyHTTPResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func Status(sc int) HTTPResponse {
|
||||||
|
return &emptyHTTPResponse{statusCode: sc}
|
||||||
|
}
|
73
ginext/responseFile.go
Normal file
73
ginext/responseFile.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fileHTTPResponse struct {
|
||||||
|
mimetype string
|
||||||
|
filepath string
|
||||||
|
filename *string
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) Write(g *gin.Context) {
|
||||||
|
g.Header("Content-Type", j.mimetype) // if we don't set it here gin does weird file-sniffing later...
|
||||||
|
if j.filename != nil {
|
||||||
|
g.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", *j.filename))
|
||||||
|
|
||||||
|
}
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
g.File(j.filepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) IsSuccess() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) Statuscode() int {
|
||||||
|
return 200
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) BodyString(*gin.Context) *string {
|
||||||
|
data, err := os.ReadFile(j.filepath)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return langext.Ptr(string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) ContentType() string {
|
||||||
|
return j.mimetype
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j fileHTTPResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func File(mimetype string, filepath string) HTTPResponse {
|
||||||
|
return &fileHTTPResponse{mimetype: mimetype, filepath: filepath}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Download(mimetype string, filepath string, filename string) HTTPResponse {
|
||||||
|
return &fileHTTPResponse{mimetype: mimetype, filepath: filepath, filename: &filename}
|
||||||
|
}
|
70
ginext/responseJson.go
Normal file
70
ginext/responseJson.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
json "gogs.mikescher.com/BlackForestBytes/goext/gojson"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jsonHTTPResponse struct {
|
||||||
|
statusCode int
|
||||||
|
data any
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) jsonRenderer(g *gin.Context) json.GoJsonRender {
|
||||||
|
var f *string
|
||||||
|
if jsonfilter := g.GetString("goext.jsonfilter"); jsonfilter != "" {
|
||||||
|
f = &jsonfilter
|
||||||
|
}
|
||||||
|
return json.GoJsonRender{Data: j.data, NilSafeSlices: true, NilSafeMaps: true, Filter: f}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) Write(g *gin.Context) {
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
g.Render(j.statusCode, j.jsonRenderer(g))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) IsSuccess() bool {
|
||||||
|
return j.statusCode >= 200 && j.statusCode <= 399
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) Statuscode() int {
|
||||||
|
return j.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) BodyString(g *gin.Context) *string {
|
||||||
|
if str, err := j.jsonRenderer(g).RenderString(); err == nil {
|
||||||
|
return &str
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) ContentType() string {
|
||||||
|
return "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonHTTPResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func JSON(sc int, data any) HTTPResponse {
|
||||||
|
return &jsonHTTPResponse{statusCode: sc, data: data}
|
||||||
|
}
|
77
ginext/responseJsonAPI.go
Normal file
77
ginext/responseJsonAPI.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type jsonAPIErrResponse struct {
|
||||||
|
err *exerr.ExErr
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) Write(g *gin.Context) {
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
exerr.Get(j.err).Output(context.Background(), g)
|
||||||
|
|
||||||
|
j.err.CallListener(exerr.MethodOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) IsSuccess() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) Statuscode() int {
|
||||||
|
return langext.Coalesce(j.err.RecursiveStatuscode(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) BodyString(*gin.Context) *string {
|
||||||
|
if str, err := j.err.ToDefaultAPIJson(); err == nil {
|
||||||
|
return &str
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) ContentType() string {
|
||||||
|
return "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j jsonAPIErrResponse) Unwrap() error {
|
||||||
|
return j.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(e error) HTTPResponse {
|
||||||
|
return &jsonAPIErrResponse{
|
||||||
|
err: exerr.FromError(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ErrWrap(e error, errorType exerr.ErrorType, msg string) HTTPResponse {
|
||||||
|
return &jsonAPIErrResponse{
|
||||||
|
err: exerr.FromError(exerr.Wrap(e, msg).WithType(errorType).Build()),
|
||||||
|
}
|
||||||
|
}
|
57
ginext/responseRedirect.go
Normal file
57
ginext/responseRedirect.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type redirectHTTPResponse struct {
|
||||||
|
statusCode int
|
||||||
|
url string
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) Write(g *gin.Context) {
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
g.Redirect(j.statusCode, j.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) IsSuccess() bool {
|
||||||
|
return j.statusCode >= 200 && j.statusCode <= 399
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) Statuscode() int {
|
||||||
|
return j.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) BodyString(*gin.Context) *string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) ContentType() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j redirectHTTPResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func Redirect(sc int, newURL string) HTTPResponse {
|
||||||
|
return &redirectHTTPResponse{statusCode: sc, url: newURL}
|
||||||
|
}
|
72
ginext/responseSeekable.go
Normal file
72
ginext/responseSeekable.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type seekableResponse struct {
|
||||||
|
data io.ReadSeeker
|
||||||
|
contentType string
|
||||||
|
filename string
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) Write(g *gin.Context) {
|
||||||
|
g.Header("Content-Type", j.contentType) // if we don't set it here http.ServeContent does weird sniffing later...
|
||||||
|
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
http.ServeContent(g.Writer, g.Request, j.filename, time.Unix(0, 0), j.data)
|
||||||
|
|
||||||
|
if clsr, ok := j.data.(io.ReadSeekCloser); ok {
|
||||||
|
err := clsr.Close()
|
||||||
|
if err != nil {
|
||||||
|
exerr.Wrap(err, "failed to close io.ReadSeerkClose in ginext.Seekable").Str("filename", j.filename).Print()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) IsSuccess() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) Statuscode() int {
|
||||||
|
return 200
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) BodyString(*gin.Context) *string {
|
||||||
|
return langext.Ptr("(seekable)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) ContentType() string {
|
||||||
|
return j.contentType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j seekableResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func Seekable(filename string, contentType string, data io.ReadSeeker) HTTPResponse {
|
||||||
|
return &seekableResponse{filename: filename, contentType: contentType, data: data}
|
||||||
|
}
|
57
ginext/responseText.go
Normal file
57
ginext/responseText.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package ginext
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
)
|
||||||
|
|
||||||
|
type textHTTPResponse struct {
|
||||||
|
statusCode int
|
||||||
|
data string
|
||||||
|
headers []headerval
|
||||||
|
cookies []cookieval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) Write(g *gin.Context) {
|
||||||
|
for _, v := range j.headers {
|
||||||
|
g.Header(v.Key, v.Val)
|
||||||
|
}
|
||||||
|
for _, v := range j.cookies {
|
||||||
|
g.SetCookie(v.name, v.value, v.maxAge, v.path, v.domain, v.secure, v.httpOnly)
|
||||||
|
}
|
||||||
|
g.String(j.statusCode, "%s", j.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) WithHeader(k string, v string) HTTPResponse {
|
||||||
|
j.headers = append(j.headers, headerval{k, v})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) WithCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) HTTPResponse {
|
||||||
|
j.cookies = append(j.cookies, cookieval{name, value, maxAge, path, domain, secure, httpOnly})
|
||||||
|
return j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) IsSuccess() bool {
|
||||||
|
return j.statusCode >= 200 && j.statusCode <= 399
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) Statuscode() int {
|
||||||
|
return j.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) BodyString(*gin.Context) *string {
|
||||||
|
return langext.Ptr(j.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) ContentType() string {
|
||||||
|
return "text/plain"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j textHTTPResponse) Headers() []string {
|
||||||
|
return langext.ArrMap(j.headers, func(v headerval) string { return v.Key + "=" + v.Val })
|
||||||
|
}
|
||||||
|
|
||||||
|
func Text(sc int, data string) HTTPResponse {
|
||||||
|
return &textHTTPResponse{statusCode: sc, data: data}
|
||||||
|
}
|
22
go.mod
22
go.mod
@@ -8,10 +8,10 @@ require (
|
|||||||
github.com/jmoiron/sqlx v1.4.0
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
github.com/rs/xid v1.5.0
|
github.com/rs/xid v1.5.0
|
||||||
github.com/rs/zerolog v1.33.0
|
github.com/rs/zerolog v1.33.0
|
||||||
go.mongodb.org/mongo-driver v1.15.0
|
go.mongodb.org/mongo-driver v1.15.1
|
||||||
golang.org/x/crypto v0.23.0
|
golang.org/x/crypto v0.24.0
|
||||||
golang.org/x/sys v0.20.0
|
golang.org/x/sys v0.21.0
|
||||||
golang.org/x/term v0.20.0
|
golang.org/x/term v0.21.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -32,13 +32,13 @@ require (
|
|||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
github.com/go-playground/validator/v10 v10.22.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.3 // indirect
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/uuid v1.5.0 // indirect
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.17.8 // indirect
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
@@ -54,10 +54,10 @@ require (
|
|||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
golang.org/x/image v0.16.0 // indirect
|
golang.org/x/image v0.17.0 // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.26.0 // indirect
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.1 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/libc v1.37.6 // indirect
|
modernc.org/libc v1.37.6 // indirect
|
||||||
modernc.org/mathutil v1.6.0 // indirect
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
24
go.sum
24
go.sum
@@ -79,6 +79,10 @@ github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn
|
|||||||
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/go-playground/validator/v10 v10.21.0 h1:4fZA11ovvtkdgaeev9RGWPgc1uj3H8W+rNYyH/ySBb0=
|
||||||
|
github.com/go-playground/validator/v10 v10.21.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
|
||||||
|
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
@@ -118,11 +122,15 @@ github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLA
|
|||||||
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
@@ -210,6 +218,8 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd
|
|||||||
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||||
go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
|
go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
|
||||||
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||||
|
go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU=
|
||||||
|
go.mongodb.org/mongo-driver v1.15.1/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
@@ -233,11 +243,15 @@ golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
|||||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||||
|
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||||
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw=
|
golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw=
|
||||||
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
|
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
|
||||||
|
golang.org/x/image v0.17.0 h1:nTRVVdajgB8zCMZVsViyzhnMKPwYeroEERRC64JuLco=
|
||||||
|
golang.org/x/image v0.17.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@@ -256,6 +270,8 @@ golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
|||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||||
|
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
@@ -283,6 +299,8 @@ golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
|||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||||
|
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||||
@@ -295,6 +313,8 @@ golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
|||||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||||
|
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@@ -305,6 +325,8 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
|||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
@@ -320,6 +342,8 @@ google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH
|
|||||||
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
package goext
|
package goext
|
||||||
|
|
||||||
const GoextVersion = "0.0.464"
|
const GoextVersion = "0.0.475"
|
||||||
|
|
||||||
const GoextVersionTimestamp = "2024-06-01T02:40:48+0200"
|
const GoextVersionTimestamp = "2024-06-16T17:14:21+0200"
|
||||||
|
@@ -474,6 +474,17 @@ func ArrAppend[T any](arr []T, add ...T) []T {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ArrPrepend works similar to append(x, y, z) - but doe snot touch the old array and creates a new one
|
||||||
|
// Also - in contrast to ArrAppend - the add values are inserted at the start of the resulting array (in reverse order)
|
||||||
|
func ArrPrepend[T any](arr []T, add ...T) []T {
|
||||||
|
out := make([]T, len(arr)+len(add))
|
||||||
|
copy(out[len(add):], arr)
|
||||||
|
for i := 0; i < len(add); i++ {
|
||||||
|
out[len(add)-i-1] = add[i]
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// ArrCopy does a shallow copy of the 'in' array
|
// ArrCopy does a shallow copy of the 'in' array
|
||||||
func ArrCopy[T any](in []T) []T {
|
func ArrCopy[T any](in []T) []T {
|
||||||
out := make([]T, len(in))
|
out := make([]T, len(in))
|
||||||
@@ -553,3 +564,18 @@ func ArrChunk[T any](arr []T, chunkSize int) [][]T {
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ArrGroupBy[T1 any, T2 comparable](arr []T1, groupfunc func(v T1) T2) map[T2][]T1 {
|
||||||
|
r := make(map[T2][]T1)
|
||||||
|
|
||||||
|
for _, v := range arr {
|
||||||
|
key := groupfunc(v)
|
||||||
|
if _, ok := r[key]; ok {
|
||||||
|
r[key] = append(r[key], v)
|
||||||
|
} else {
|
||||||
|
r[key] = []T1{v}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package langext
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/tst"
|
"gogs.mikescher.com/BlackForestBytes/goext/tst"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -10,3 +11,13 @@ func TestJoinString(t *testing.T) {
|
|||||||
res := JoinString(ids, ",")
|
res := JoinString(ids, ",")
|
||||||
tst.AssertEqual(t, res, "1,2,3")
|
tst.AssertEqual(t, res, "1,2,3")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestArrPrepend(t *testing.T) {
|
||||||
|
v1 := []string{"1", "2", "3"}
|
||||||
|
|
||||||
|
v2 := ArrPrepend(v1, "4", "5", "6")
|
||||||
|
|
||||||
|
tst.AssertEqual(t, strings.Join(v1, ""), "123")
|
||||||
|
tst.AssertEqual(t, strings.Join(v2, ""), "654123")
|
||||||
|
|
||||||
|
}
|
||||||
|
@@ -77,6 +77,14 @@ func Coalesce4Opt[T any](v1 *T, v2 *T, v3 *T, v4 *T) *T {
|
|||||||
return v4
|
return v4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CoalesceDblPtr[T any](v1 **T, v2 *T) *T {
|
||||||
|
if v1 != nil {
|
||||||
|
return *v1
|
||||||
|
}
|
||||||
|
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
func CoalesceString(s *string, def string) string {
|
func CoalesceString(s *string, def string) string {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return def
|
return def
|
||||||
|
@@ -22,6 +22,13 @@ func DblPtr[T any](v T) **T {
|
|||||||
return &v_
|
return &v_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DblPtrIfNotNil[T any](v *T) **T {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
func DblPtrNil[T any]() **T {
|
func DblPtrNil[T any]() **T {
|
||||||
var v *T = nil
|
var v *T = nil
|
||||||
return &v
|
return &v
|
||||||
|
@@ -1,13 +1,14 @@
|
|||||||
package pagination
|
package pagination
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MongoFilter interface {
|
type MongoFilter interface {
|
||||||
FilterQuery() mongo.Pipeline
|
FilterQuery(ctx context.Context) mongo.Pipeline
|
||||||
Sort() bson.D
|
Sort(ctx context.Context) bson.D
|
||||||
}
|
}
|
||||||
|
|
||||||
type dynamicFilter struct {
|
type dynamicFilter struct {
|
||||||
@@ -15,11 +16,11 @@ type dynamicFilter struct {
|
|||||||
sort bson.D
|
sort bson.D
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dynamicFilter) FilterQuery() mongo.Pipeline {
|
func (d dynamicFilter) FilterQuery(ctx context.Context) mongo.Pipeline {
|
||||||
return d.pipeline
|
return d.pipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dynamicFilter) Sort() bson.D {
|
func (d dynamicFilter) Sort(ctx context.Context) bson.D {
|
||||||
return d.sort
|
return d.sort
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,8 +25,8 @@ func (c *Coll[TData]) List(ctx context.Context, filter ct.Filter, pageSize *int,
|
|||||||
pd2 := ct.SortASC
|
pd2 := ct.SortASC
|
||||||
|
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
pipeline = filter.FilterQuery()
|
pipeline = filter.FilterQuery(ctx)
|
||||||
pf1, pd1, pf2, pd2 = filter.Pagination()
|
pf1, pd1, pf2, pd2 = filter.Pagination(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
sortPrimary := pf1
|
sortPrimary := pf1
|
||||||
@@ -109,7 +109,7 @@ func (c *Coll[TData]) Count(ctx context.Context, filter ct.RawFilter) (int64, er
|
|||||||
Count int64 `bson:"c"`
|
Count int64 `bson:"c"`
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline := filter.FilterQuery()
|
pipeline := filter.FilterQuery(ctx)
|
||||||
|
|
||||||
pipeline = append(pipeline, bson.D{{Key: "$count", Value: "c"}})
|
pipeline = append(pipeline, bson.D{{Key: "$count", Value: "c"}})
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ func (c *Coll[TData]) ListAllIDs(ctx context.Context, filter ct.RawFilter) ([]st
|
|||||||
pipelineFilter := mongo.Pipeline{}
|
pipelineFilter := mongo.Pipeline{}
|
||||||
|
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
pipelineFilter = filter.FilterQuery()
|
pipelineFilter = filter.FilterQuery(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
extrModPipelineResolved := mongo.Pipeline{}
|
extrModPipelineResolved := mongo.Pipeline{}
|
||||||
|
@@ -23,8 +23,8 @@ func (c *Coll[TData]) Paginate(ctx context.Context, filter pag.MongoFilter, page
|
|||||||
sort := bson.D{}
|
sort := bson.D{}
|
||||||
|
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
pipelineFilter = filter.FilterQuery()
|
pipelineFilter = filter.FilterQuery(ctx)
|
||||||
sort = filter.Sort()
|
sort = filter.Sort(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sort) != 0 {
|
if len(sort) != 0 {
|
||||||
|
Reference in New Issue
Block a user