From 80df46dbc87b4c20629a768e18517f86bafd6f56 Mon Sep 17 00:00:00 2001 From: vagarwal-viant Date: Thu, 10 Jul 2025 14:58:18 -0700 Subject: [PATCH 001/117] ENG-00000 remove trim of nongraphic characters --- gateway/router/marshal/json/marshaller_strings.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gateway/router/marshal/json/marshaller_strings.go b/gateway/router/marshal/json/marshaller_strings.go index bb2a8ebd8..322dd53a0 100644 --- a/gateway/router/marshal/json/marshaller_strings.go +++ b/gateway/router/marshal/json/marshaller_strings.go @@ -5,7 +5,6 @@ import ( "github.com/viant/tagly/format" "github.com/viant/xunsafe" "strings" - "unicode" "unsafe" ) @@ -51,9 +50,12 @@ func (i *stringMarshaller) ensureReplacer() { } func marshallString(asString string, sb *MarshallSession, replacer *strings.Replacer) { - asString = strings.TrimFunc(asString, func(r rune) bool { - return !unicode.IsGraphic(r) - }) + // This removes all /n characters at begining and end of log lines in CI_EVENT Table + /* + asString = strings.TrimFunc(asString, func(r rune) bool { + return !unicode.IsGraphic(r) + }) + */ sb.WriteByte('"') sb.WriteString(replacer.Replace(asString)) From 41fc97d1d1c6b5d97061f50d4d0b75708690ea25 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 22 Aug 2025 10:47:06 -0700 Subject: [PATCH 002/117] fixed nil pointer --- go.sum | 2 -- internal/translator/service.go | 14 +++++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/go.sum b/go.sum index 736b0b41e..5d442daa1 100644 --- a/go.sum +++ b/go.sum @@ -1141,8 +1141,6 @@ github.com/viant/scy v0.24.0 h1:KAC3IUARkQxTNSuwBK2YhVBJMOOLN30YaLKHbbuSkMU= github.com/viant/scy v0.24.0/go.mod h1:7uNRS67X45YN+JqTLCcMEhehffVjqrejULEDln9p0Ao= github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns= github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= -github.com/viant/sqlx v0.16.6 h1:3/D1/c3E8cMaUWTUBW56Gg/1vW4QMMWm42HkSAbzSZQ= -github.com/viant/sqlx v0.16.6/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/sqlx v0.17.6 h1:6uMZVWk+WJl/y8coEh4F4mqbTHbtzWkLVEQdrk+m7sE= github.com/viant/sqlx v0.17.6/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= diff --git a/internal/translator/service.go b/internal/translator/service.go index 66c9ccabb..d53f4e6a3 100644 --- a/internal/translator/service.go +++ b/internal/translator/service.go @@ -4,6 +4,12 @@ import ( "context" "database/sql" "fmt" + "net/http" + spath "path" + "reflect" + "strings" + "time" + "github.com/viant/afs" "github.com/viant/afs/file" "github.com/viant/afs/url" @@ -27,11 +33,6 @@ import ( "github.com/viant/xreflect" "golang.org/x/mod/modfile" "gopkg.in/yaml.v3" - "net/http" - spath "path" - "reflect" - "strings" - "time" ) type Service struct { @@ -449,6 +450,9 @@ func (s *Service) adjustView(viewlet *Viewlet, resource *Resource, mode view.Mod } if viewlet.TypeDefinition != nil { if viewlet.TypeDefinition.Cardinality == state.Many { + if viewlet.View.View.Schema == nil { + viewlet.View.View.Schema = &state.Schema{} + } viewlet.View.View.Schema.Cardinality = viewlet.TypeDefinition.Cardinality } viewlet.TypeDefinition.Cardinality = "" From 69bf4ff272e6c68373a5216a3801187125648d1e Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 22 Aug 2025 12:15:22 -0700 Subject: [PATCH 003/117] fixed logger merge issue --- gateway/router.go | 9 +- gateway/router/handler.go | 9 +- repository/contract/dispatcher.go | 9 + .../component/dispatcher/disptacher.go | 1 + service/executor/handler/executor.go | 11 +- service/executor/handler/options.go | 8 + service/session/option.go | 7 + shared/logging/logger.go | 410 ++++++++++++++++++ 8 files changed, 459 insertions(+), 5 deletions(-) create mode 100644 shared/logging/logger.go diff --git a/gateway/router.go b/gateway/router.go index 5da821bd0..a63bf8a98 100644 --- a/gateway/router.go +++ b/gateway/router.go @@ -18,11 +18,14 @@ import ( "github.com/viant/datly/repository/path" "github.com/viant/datly/service/operator" "github.com/viant/datly/service/session" + "github.com/viant/datly/shared/logging" "github.com/viant/datly/view" vcontext "github.com/viant/datly/view/context" + "github.com/viant/datly/view/state/kind/locator" "github.com/viant/gmetric" serverproto "github.com/viant/mcp-protocol/server" "github.com/viant/xdatly/handler/async" + "github.com/viant/xdatly/handler/logger" hstate "github.com/viant/xdatly/handler/state" "net/http" @@ -38,6 +41,7 @@ type ( repository *repository.Service operator *operator.Service config *Config + logger logger.Logger OpenAPIInfo openapi3.Info metrics *gmetric.Service statusHandler http.Handler @@ -78,6 +82,7 @@ func NewRouter(ctx context.Context, components *repository.Service, config *Conf operator: operator.New(), apiKeyMatcher: newApiKeyMatcher(config.APIKeys), mcpRegistry: mcpRegistry, + logger: logging.New(logging.INFO, nil), } return r, r.init(ctx) } @@ -154,8 +159,10 @@ func (r *Router) HandleJob(ctx context.Context, aJob *async.Job) error { request := &http.Request{Method: aJob.Method, URL: URL, RequestURI: aPath.URI} unmarshal := aComponent.UnmarshalFunc(request) locatorOptions := append(aComponent.LocatorOptions(request, hstate.NewForm(), unmarshal)) + locatorOptions = append(locatorOptions, locator.WithLogger(r.logger)) aSession := session.New(aComponent.View, session.WithAuth(r.repository.Auth()), + session.WithLogger(r.logger), session.WithComponent(aComponent), session.WithLocatorOptions(locatorOptions...), session.WithOperate(r.operator.Operate)) @@ -342,7 +349,7 @@ func (r *Router) newMatcher(ctx context.Context) (*matcher.Matcher, []*contract. } r.EnsureCors(aPath) - aRoute := r.NewRouteHandler(router.New(aPath, provider, r.repository.Registry(), r.repository.Auth(), r.config.Version, r.config.Logging)) + aRoute := r.NewRouteHandler(router.New(aPath, provider, r.repository.Registry(), r.repository.Auth(), r.config.Version, r.config.Logging, r.logger)) routes = append(routes, aRoute) if aPath.Cors != nil { optionsPaths[aPath.URI] = append(optionsPaths[aPath.URI], aPath) diff --git a/gateway/router/handler.go b/gateway/router/handler.go index b45917b65..ce7398a41 100644 --- a/gateway/router/handler.go +++ b/gateway/router/handler.go @@ -27,7 +27,9 @@ import ( "github.com/viant/datly/view" vcontext "github.com/viant/datly/view/context" "github.com/viant/datly/view/state" + "github.com/viant/datly/view/state/kind/locator" "github.com/viant/xdatly/handler/exec" + "github.com/viant/xdatly/handler/logger" "github.com/viant/xdatly/handler/response" hstate "github.com/viant/xdatly/handler/state" "io" @@ -54,6 +56,7 @@ type ( registry *repository.Registry auth *auth.Service logging logging.Config + logger logger.Logger } ) @@ -87,7 +90,7 @@ func (r *Handler) AuthorizeRequest(request *http.Request, aPath *path.Path) erro return nil } -func New(aPath *path.Path, provider *repository.Provider, registry *repository.Registry, authService *auth.Service, version string, config logging.Config) *Handler { +func New(aPath *path.Path, provider *repository.Provider, registry *repository.Registry, authService *auth.Service, version string, config logging.Config, logger logger.Logger) *Handler { ret := &Handler{ Path: aPath, Provider: provider, @@ -96,6 +99,7 @@ func New(aPath *path.Path, provider *repository.Provider, registry *repository.R auth: authService, Version: version, logging: config, + logger: logger, } return ret } @@ -390,11 +394,14 @@ func (r *Handler) handleComponent(ctx context.Context, request *http.Request, aC anOperator := operator.New() unmarshal := aComponent.UnmarshalFunc(request) locatorOptions := append(aComponent.LocatorOptions(request, hstate.NewForm(), unmarshal)) + locatorOptions = append(locatorOptions, locator.WithLogger(r.logger)) aSession := session.New(aComponent.View, session.WithAuth(r.auth), + session.WithLogger(r.logger), session.WithComponent(aComponent), session.WithLocatorOptions(locatorOptions...), session.WithRegistry(r.registry), + session.WithOperate(anOperator.Operate)) err := aSession.InitKinds(state.KindComponent, state.KindHeader, state.KindRequestBody, state.KindForm, state.KindQuery) if err != nil { diff --git a/repository/contract/dispatcher.go b/repository/contract/dispatcher.go index 22afc3d26..6da3f9f72 100644 --- a/repository/contract/dispatcher.go +++ b/repository/contract/dispatcher.go @@ -2,6 +2,7 @@ package contract import ( "context" + "github.com/viant/xdatly/handler/logger" hstate "github.com/viant/xdatly/handler/state" "net/http" "net/url" @@ -16,6 +17,7 @@ type ( Header http.Header Form *hstate.Form Request *http.Request + Logger logger.Logger } //Option represents a dispatcher option Option func(o *Options) @@ -77,3 +79,10 @@ func WithRequest(request *http.Request) Option { o.Request = request } } + +// WithLogger adds path parameters +func WithLogger(loger logger.Logger) Option { + return func(o *Options) { + o.Logger = loger + } +} diff --git a/repository/locator/component/dispatcher/disptacher.go b/repository/locator/component/dispatcher/disptacher.go index 0ea2fbd3b..0c13a136f 100644 --- a/repository/locator/component/dispatcher/disptacher.go +++ b/repository/locator/component/dispatcher/disptacher.go @@ -47,6 +47,7 @@ func (d *Dispatcher) Dispatch(ctx context.Context, path *contract.Path, opts ... aSession := session.New(aComponent.View, session.WithLocatorOptions(options...), session.WithAuth(d.auth), session.WithRegistry(d.registry), + session.WithLogger(cOptions.Logger), session.WithComponent(aComponent), session.WithOperate(d.service.Operate)) ctx = aSession.Context(ctx, true) diff --git a/service/executor/handler/executor.go b/service/executor/handler/executor.go index 4d5e719ae..ce20877d0 100644 --- a/service/executor/handler/executor.go +++ b/service/executor/handler/executor.go @@ -4,6 +4,8 @@ import ( "context" "database/sql" "fmt" + "net/http" + "github.com/viant/datly/repository" "github.com/viant/datly/repository/contract" executor "github.com/viant/datly/service/executor" @@ -20,7 +22,6 @@ import ( "github.com/viant/xdatly/handler/sqlx" hstate "github.com/viant/xdatly/handler/state" "github.com/viant/xdatly/handler/validator" - "net/http" ) type ( @@ -126,6 +127,9 @@ func (e *Executor) newSession(aSession *session.Session, opts ...Option) *extens if options.auth != nil { e.auth = options.auth } + if e.logger == nil { + e.logger = options.logger + } res := e.view.GetResource() sess := extension.NewSession( extension.WithTemplateFlush(func(ctx context.Context) error { @@ -135,6 +139,7 @@ func (e *Executor) newSession(aSession *session.Session, opts ...Option) *extens extension.WithRedirect(e.redirect), extension.WithSql(e.newSqlService), extension.WithHttp(e.newHttp), + extension.WithLogger(e.logger), extension.WithAuth(e.newAuth), extension.WithMessageBus(res.MessageBuses), ) @@ -262,7 +267,6 @@ func (e *Executor) redirect(ctx context.Context, route *http2.Route, opts ...hst request.Header = originalRequest.Header } stateOptions := hstate.NewOptions(opts...) - unmarshal := aComponent.UnmarshalFunc(request) locatorOptions := append(aComponent.LocatorOptions(request, hstate.NewForm(), unmarshal)) if stateOptions.Query() != nil { @@ -286,6 +290,7 @@ func (e *Executor) redirect(ctx context.Context, route *http2.Route, opts ...hst session.WithOperate(e.session.Options.Operate()), session.WithTypes(&aComponent.Contract.Input.Type, &aComponent.Contract.Output.Type), session.WithComponent(aComponent), + session.WithLogger(e.logger), session.WithRegistry(registry), ) @@ -295,7 +300,7 @@ func (e *Executor) redirect(ctx context.Context, route *http2.Route, opts ...hst } ctx = aSession.Context(ctx, true) anExecutor := NewExecutor(aComponent.View, aSession) - return anExecutor.NewHandlerSession(ctx) + return anExecutor.NewHandlerSession(ctx, WithLogger(aSession.Logger())) } func (e *Executor) newHttp() http2.Http { diff --git a/service/executor/handler/options.go b/service/executor/handler/options.go index 538e130df..e1221318b 100644 --- a/service/executor/handler/options.go +++ b/service/executor/handler/options.go @@ -4,6 +4,7 @@ import ( "embed" "github.com/viant/datly/service/auth" "github.com/viant/datly/view/state" + "github.com/viant/xdatly/handler/logger" ) type options struct { @@ -11,6 +12,7 @@ type options struct { embedFS *embed.FS opts []Option auth *auth.Service + logger logger.Logger } func (o *options) Clone(opts []Option) *options { @@ -37,6 +39,12 @@ func WithTypes(types ...*state.Type) Option { } } +func WithLogger(logger logger.Logger) Option { + return func(o *options) { + o.logger = logger + } +} + func WithAuth(auth *auth.Service) Option { return func(o *options) { o.auth = auth diff --git a/service/session/option.go b/service/session/option.go index 0fc7ea6a0..148242cb4 100644 --- a/service/session/option.go +++ b/service/session/option.go @@ -3,6 +3,7 @@ package session import ( "context" "embed" + "github.com/viant/datly/repository" "github.com/viant/datly/service/auth" "github.com/viant/datly/view" @@ -183,3 +184,9 @@ func WithRegistry(registry *repository.Registry) Option { s.registry = registry } } + +func WithLogger(logger logger.Logger) Option { + return func(s *Options) { + s.logger = logger + } +} diff --git a/shared/logging/logger.go b/shared/logging/logger.go new file mode 100644 index 000000000..aea30470f --- /dev/null +++ b/shared/logging/logger.go @@ -0,0 +1,410 @@ +package logging + +import ( + "context" + "encoding/json" + "fmt" + "github.com/aws/aws-lambda-go/events" + "github.com/viant/xdatly/handler/logger" + "io" + "log/slog" + "os" + regexp "regexp" + "runtime" + strings "strings" +) + +const ( + ReqId = "RequestId" + OpenTelemetryTraceId = "OpenTelemetryTraceId" + DEBUG = "DEBUG" + INFO = "INFO" + WARN = "WARN" + ERROR = "ERROR" + UNKNOWN = "UNKNOWN" // Indicate other environment +) + +type slogger struct { + logger *slog.Logger + level slog.Level +} + +// Init creates an ISLogger instance, a structured logger using the JSON Handler. +// Creating this logger sets this as the default logger, so any logging after this +// which goes through the standard logging package will also produce JSON structured +// logs. +func New(level string, dest io.Writer) logger.Logger { + if dest == nil { + dest = os.Stdout + } + + logLevel := slog.LevelInfo + switch strings.ToUpper(level) { + case DEBUG: + logLevel = slog.LevelDebug + case WARN: + logLevel = slog.LevelWarn + case ERROR: + logLevel = slog.LevelError + } + + handler := slog.NewJSONHandler(dest, &slog.HandlerOptions{ + AddSource: false, + Level: logLevel, + ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { + // Rename the time key to "timestamp" + if a.Key == slog.TimeKey { + a.Key = "timestamp" + } + return a + }, + }) + sl := slog.New(handler) + slog.SetDefault(sl) + logger := &slogger{sl, logLevel} + + return logger +} + +func (s *slogger) IsDebugEnabled() bool { + return s.level.Level() <= slog.LevelDebug +} + +func (s *slogger) IsInfoEnabled() bool { + return s.level.Level() <= slog.LevelInfo +} + +func (s *slogger) IsWarnEnabled() bool { + return s.level.Level() <= slog.LevelWarn +} + +func (s *slogger) IsErrorEnabled() bool { + return s.level.Level() <= slog.LevelError +} + +// getCallerInfo uses runtime to get the caller's program counter +// and extract info from the stack frame to get the function name, etc. +func (s *slogger) getCallerInfo() []any { + callers := make([]uintptr, 1) + count := runtime.Callers(3, callers[:]) // skip to actual caller + if count == 0 { + slog.Warn("getCallerInfo: no frames, exiting") + return nil + } + + frames := runtime.CallersFrames(callers) + var frame runtime.Frame + var more bool + for { + frame, more = frames.Next() + if !more { + break + } + } + + attr := []any{ + "function", frame.Function, "file", frame.File, "line", frame.Line, + } + + return attr +} + +// getContextValues retrieves "known" logging values from the Context. +// These values can be added to the Context using the provided utility functions. +func (s *slogger) getContextValues(ctx context.Context) []any { + var values []any + if ctx == nil { + slog.Warn("getContextValues: ctx is nil") + return nil + } + + openTelemetryTraceId := ctx.Value(OpenTelemetryTraceId) + if openTelemetryTraceId != nil { + values = append(values, "OpenTelemetryTraceId", openTelemetryTraceId) + } + return values +} + +// Info wraps a call to slog.Info, inserting details for the calling function. +func (s *slogger) Info(msg string, args ...any) { + if !s.IsInfoEnabled() { + return + } + caller := s.getCallerInfo() + caller = append(caller, args...) + s.logger.Info(msg, caller...) +} + +// Debug wraps a call to slog.Debug, inserting details for the calling function. +func (s *slogger) Debug(msg string, args ...any) { + if !s.IsDebugEnabled() { + return + } + caller := s.getCallerInfo() + caller = append(caller, args...) + s.logger.Debug(msg, caller...) +} + +// Warn wraps a call to slog.Warn, inserting details for the calling function. +func (s *slogger) Warn(msg string, args ...any) { + if !s.IsWarnEnabled() { + return + } + caller := s.getCallerInfo() + caller = append(caller, args...) + s.logger.Warn(msg, caller...) +} + +// Error wraps a call to slog.Error, inserting details for the calling function. +func (s *slogger) Error(msg string, args ...any) { + if !s.IsErrorEnabled() { + return + } + caller := s.getCallerInfo() + caller = append(caller, args...) + s.logger.Error(msg, caller...) +} + +// Infoc wraps a call to slog.Info, inserting details for the calling function, +// and retrieving known values from the context object. +func (s *slogger) Infoc(ctx context.Context, msg string, args ...any) { + if !s.IsInfoEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, args...) + s.logger.Info(msg, caller...) +} + +func (s *slogger) Infos(ctx context.Context, msg string, attrs ...slog.Attr) { + if !s.IsInfoEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, redactAttrs(attrs...)...) + + s.logger.Info(msg, caller...) +} + +// Debugc wraps a call to slog.Debug, inserting details for the calling function, +// and retrieving known values from the context object. +func (s *slogger) Debugc(ctx context.Context, msg string, args ...any) { + if !s.IsDebugEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, args...) + s.logger.Debug(msg, caller...) +} + +func (s *slogger) Debugs(ctx context.Context, msg string, attrs ...slog.Attr) { + if !s.IsDebugEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, redactAttrs(attrs...)...) + + s.logger.Debug(msg, caller...) +} + +// DebugJSONc wraps a call to slog.Debug, inserting details for the calling function, +// and retrieving known values from the context object. +func (s *slogger) DebugJSONc(ctx context.Context, msg string, obj any) { + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + + // Initialize request and jsonData variables + var request events.APIGatewayProxyRequest + var jsonData []byte + // Marshal the object to JSON string + jsonString, _ := json.Marshal(obj) + // Unmarshal JSON string to APIGatewayProxyRequest + err := json.Unmarshal(jsonString, &request) + if err != nil { + return + } + + // Check if the request has an HTTP method + if len(request.HTTPMethod) > 0 { + if request.MultiValueHeaders == nil { + request.MultiValueHeaders = make(map[string][]string) + } + // Remove Authorization header + request.MultiValueHeaders["Authorization"] = nil + request.Headers["Authorization"] = "" + // Marshal the modified request to JSON + jsonData, _ = json.Marshal(request) + } else { + jsonData = jsonString + } + msg = fmt.Sprintf("%s %s", msg, string(jsonData)) + s.Debugc(ctx, msg, caller...) +} + +// Warnc wraps a call to slog.Warn, inserting details for the calling function, +// and retrieving known values from the context object. +func (s *slogger) Warnc(ctx context.Context, msg string, args ...any) { + if !s.IsWarnEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, args...) + s.logger.Warn(msg, caller...) +} + +func (s *slogger) Warns(ctx context.Context, msg string, attrs ...slog.Attr) { + if !s.IsWarnEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, redactAttrs(attrs...)...) + + s.logger.Warn(msg, caller...) +} + +// Errorc wraps a call to slog.Error, inserting details for the calling function, +// and retrieving known values from the context object. +func (s *slogger) Errorc(ctx context.Context, msg string, args ...any) { + if !s.IsErrorEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, args...) + s.logger.Error(msg, caller...) +} + +func (s *slogger) Errors(ctx context.Context, msg string, attrs ...slog.Attr) { + if !s.IsErrorEnabled() { + return + } + caller := s.getCallerInfo() + values := s.getContextValues(ctx) + caller = append(caller, values...) + caller = append(caller, redactAttrs(attrs...)...) + + s.logger.Error(msg, caller...) +} + +// Helper to get platform from environment suffix +func getPlatformFromEnv(environment string) string { + switch { + case strings.Contains(environment, "dev"): + return "development" + case strings.Contains(environment, "stage"): + return "stage" + case strings.Contains(environment, "prod"): + return "production" + default: + return UNKNOWN + } +} + +// redactAttrs applies redaction rules to slog.Attr list. +// Skip redactValue for primitive types to avoid unnecessary processing +// This avoids redundant type switch/marshalling cost in high-volume logging +func redactAttrs(attrs ...slog.Attr) []any { + var result []any + for _, attr := range attrs { + if isSensitiveKey(attr.Key) { + result = append(result, slog.String(attr.Key, "[REDACTED]")) + continue + } + val := attr.Value.Any() + switch val.(type) { + case int, int64, float64, bool, nil: + result = append(result, attr) + default: + redactedValue := slog.AnyValue(redactValue(val)) + result = append(result, slog.Attr{Key: attr.Key, Value: redactedValue}) + } + } + return result +} + +// redactValue recursively redacts sensitive info in maps, slices, or structs. +func redactValue(value any) any { + switch v := value.(type) { + case string: + // Redact sensitive information in strings + return redactSensitiveInfo(v) + case int, int64, float64, bool, nil: + // Return primitive values directly (skip JSON marshalling) + return v + case map[string]any: + // Redact value if key is sensitive (e.g., Authorization → [REDACTED]) + // Ensures map fields are redacted even if value doesn’t match regex + for key, val := range v { + if isSensitiveKey(key) { + v[key] = "[REDACTED]" + } else { + v[key] = redactValue(val) + } + } + return v + case []any: + // Recursively redact sensitive information in slices + for i, val := range v { + v[i] = redactValue(val) + } + return v + default: + // Only marshal/unmarshal if absolutely needed (structs, unknown). + jsonData, err := json.Marshal(v) // Converts struct to map to enable nested field redaction. + if err != nil { + return v // If marshal fails, skip redaction + } + var unmarshaled any + if err := json.Unmarshal(jsonData, &unmarshaled); err != nil { + return v // If unmarshal fails, skip redaction + } + return redactValue(unmarshaled) + } +} + +// redactSensitiveInfo redacts known patterns in a string (e.g., tokens in URLs). +func redactSensitiveInfo(value string) string { + sensitivePatterns := []*regexp.Regexp{ + // Redact key=value style + regexp.MustCompile(`(?i)(X-Amz-Security-Token|X-Amz-Signature|X-Amz-Credential|Authorization|password|token|apiKey)=([^&\s]+)`), + // Redact key: value or key value + regexp.MustCompile(`(?i)(Authorization|password|token|apiKey)[\s:=]+([^&\s]+)`), + // Redact URL with user:pass@host + regexp.MustCompile(`(?i)https?://[^/]+:[^@]+@`), + } + + redacted := value + for _, pattern := range sensitivePatterns { + redacted = pattern.ReplaceAllString(redacted, "$1=[REDACTED]") + } + return redacted +} + +// isSensitiveKey returns true if the key is known to contain sensitive data. +func isSensitiveKey(key string) bool { + sensitiveKeys := []string{ + "authorization", "token", "apikey", "password", + "credential", "secret", "access_key", "secret_key", + } + key = strings.ToLower(key) + for _, sk := range sensitiveKeys { + if key == sk { + return true + } + } + return false +} From ac2a99fa866b311096e368e932578311584417ee Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 22 Aug 2025 13:15:35 -0700 Subject: [PATCH 004/117] patched slicelen issue --- service/executor/expand/data_unit.go | 2 +- service/executor/expand/state.go | 1 + service/reader/service.go | 10 ++++++---- view/state/kind/locator/repeated.go | 7 ++++--- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/service/executor/expand/data_unit.go b/service/executor/expand/data_unit.go index 66a694dad..ac7d62452 100644 --- a/service/executor/expand/data_unit.go +++ b/service/executor/expand/data_unit.go @@ -48,7 +48,7 @@ func (c *DataUnit) Reset() { c.mu.Lock() c.placeholderCounter = 0 if len(c.ParamsGroup) > 0 { - c.ParamsGroup = c.ParamsGroup[:0] + clear(c.ParamsGroup) } c.TemplateSQL = "" c.mu.Unlock() diff --git a/service/executor/expand/state.go b/service/executor/expand/state.go index f970ff679..a69767fdb 100644 --- a/service/executor/expand/state.go +++ b/service/executor/expand/state.go @@ -2,6 +2,7 @@ package expand import ( "context" + "github.com/viant/datly/service/executor/extension" "github.com/viant/datly/view/state/predicate" diff --git a/service/reader/service.go b/service/reader/service.go index 29f1fea7d..63ca09436 100644 --- a/service/reader/service.go +++ b/service/reader/service.go @@ -4,6 +4,11 @@ import ( "context" "database/sql" "fmt" + "reflect" + "sync" + "time" + "unsafe" + "github.com/google/uuid" "github.com/viant/datly/service/executor/expand" "github.com/viant/datly/shared" @@ -19,10 +24,6 @@ import ( "github.com/viant/xdatly/handler" "github.com/viant/xdatly/handler/exec" "github.com/viant/xdatly/handler/response" - "reflect" - "sync" - "time" - "unsafe" ) // Service represents reader service @@ -183,6 +184,7 @@ func (s *Service) readAll(ctx context.Context, session *Session, collector *view } return } + // if onRelationalConcurrency > 1 , then only we call it concurrently concurrencyLimit := make(chan struct{}, onRelationerConcurrency) var onRelationWaitGroup sync.WaitGroup diff --git a/view/state/kind/locator/repeated.go b/view/state/kind/locator/repeated.go index d40972b4f..1d07fde50 100644 --- a/view/state/kind/locator/repeated.go +++ b/view/state/kind/locator/repeated.go @@ -3,12 +3,13 @@ package locator import ( "context" "fmt" - "github.com/viant/datly/view/state" - "github.com/viant/datly/view/state/kind" - "github.com/viant/xunsafe" "reflect" "sync" "sync/atomic" + + "github.com/viant/datly/view/state" + "github.com/viant/datly/view/state/kind" + "github.com/viant/xunsafe" ) type Repeated struct { From 4d4d7045c3161138b107afc522ce44a40426533d Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 22 Aug 2025 13:32:27 -0700 Subject: [PATCH 005/117] patched logger nil --- repository/locator/component/component.go | 26 ++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/repository/locator/component/component.go b/repository/locator/component/component.go index 1db480628..9fd8f6dea 100644 --- a/repository/locator/component/component.go +++ b/repository/locator/component/component.go @@ -3,27 +3,31 @@ package component import ( "context" "fmt" + "net/http" + "net/url" + "reflect" + "github.com/viant/datly/repository/contract" "github.com/viant/datly/shared" "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind" "github.com/viant/datly/view/state/kind/locator" + "github.com/viant/xdatly/handler/logger" "github.com/viant/xdatly/handler/response" hstate "github.com/viant/xdatly/handler/state" "github.com/viant/xunsafe" - "net/http" - "net/url" - "reflect" ) type componentLocator struct { - custom []interface{} - dispatch contract.Dispatcher - constants map[string]interface{} - path map[string]string - form *hstate.Form - query url.Values - header http.Header + custom []interface{} + dispatch contract.Dispatcher + constants map[string]interface{} + path map[string]string + form *hstate.Form + query url.Values + header http.Header + logger logger.Logger + getRequest func() (*http.Request, error) } @@ -43,6 +47,7 @@ func (l *componentLocator) Value(ctx context.Context, name string) (interface{}, contract.WithPath(l.path), contract.WithQuery(l.query), contract.WithForm(form), + contract.WithLogger(l.logger), contract.WithHeader(l.header), ) err = updateErrWithResponseStatus(err, value) @@ -102,6 +107,7 @@ func newComponentLocator(opts ...locator.Option) (kind.Locator, error) { dispatch: options.Dispatcher, constants: options.Constants, getRequest: options.GetRequest, + logger: options.Logger, form: options.Form, query: options.Query, header: options.Header, From 9939b7c7f330d4845fd5b58164cec3b8aab0c5d6 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 22 Aug 2025 13:42:32 -0700 Subject: [PATCH 006/117] patched logger nil --- service/operator/executor.go | 5 ++++- service/reader/handler/handler.go | 10 +++++++--- service/session/state.go | 1 + service/session/stater.go | 8 +++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/service/operator/executor.go b/service/operator/executor.go index 94ba9c1b6..53915c0ba 100644 --- a/service/operator/executor.go +++ b/service/operator/executor.go @@ -3,12 +3,13 @@ package operator import ( "context" "fmt" + "time" + "github.com/viant/datly/repository" "github.com/viant/datly/repository/contract" "github.com/viant/datly/service/executor/handler" "github.com/viant/gmetric/counter" xhandler "github.com/viant/xdatly/handler" - "time" "github.com/viant/datly/service/session" "github.com/viant/datly/view/state/kind/locator" @@ -59,6 +60,8 @@ func (s *Service) execute(ctx context.Context, aComponent *repository.Component, status := contract.StatusSuccess(executorSession.TemplateState) if err := aSession.SetState(ctx, aComponent.Output.Type.Parameters, responseState, aSession.Indirect(true, locator.WithCustom(&status), + locator.WithLogger(aSession.Logger()), + locator.WithState(statelet.Template))); err != nil { return nil, fmt.Errorf("failed to set response %w", err) } diff --git a/service/reader/handler/handler.go b/service/reader/handler/handler.go index 83d47d11e..c3a485dc1 100644 --- a/service/reader/handler/handler.go +++ b/service/reader/handler/handler.go @@ -2,6 +2,7 @@ package handler import ( "context" + goJson "github.com/goccy/go-json" "github.com/viant/datly/gateway/router/status" _ "github.com/viant/datly/repository/locator/async" @@ -10,6 +11,9 @@ import ( _ "github.com/viant/datly/repository/locator/output" _ "github.com/viant/datly/service/executor/handler/locator" + "net/http" + "reflect" + reader "github.com/viant/datly/service/reader" "github.com/viant/datly/service/session" "github.com/viant/datly/utils/httputils" @@ -18,8 +22,6 @@ import ( "github.com/viant/datly/view/state/kind/locator" "github.com/viant/structology" "github.com/viant/xdatly/handler/response" - "net/http" - "reflect" ) type ( @@ -65,7 +67,9 @@ func (h *Handler) Handle(ctx context.Context, aView *view.View, aSession *sessio resultState := h.output.NewState() statelet := aSession.State().Lookup(aView) - var locatorOptions []locator.Option + var locatorOptions = []locator.Option{ + locator.WithLogger(aSession.Logger()), + } locatorOptions = append(locatorOptions, locator.WithParameterLookup(func(ctx context.Context, parameter *state.Parameter) (interface{}, bool, error) { return aSession.LookupValue(ctx, parameter, aSession.Indirect(true, locatorOptions...)) }), diff --git a/service/session/state.go b/service/session/state.go index 62a75f07f..7fcfb5c70 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -168,6 +168,7 @@ func (s *Session) viewLookupOptions(aView *view.View, parameters state.NamedPara if !opts.HasInputParameters() { result = append(result, locator.WithInputParameters(parameters)) } + result = append(result, locator.WithLogger(s.logger)) result = append(result, locator.WithReadInto(s.ReadInto)) viewState := s.state.Lookup(aView) result = append(result, locator.WithState(viewState.Template)) diff --git a/service/session/stater.go b/service/session/stater.go index 2c75bcbe9..ed50be0b3 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -2,11 +2,12 @@ package session import ( "context" + "reflect" + "github.com/viant/datly/utils/types" "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind/locator" hstate "github.com/viant/xdatly/handler/state" - "reflect" ) func (s *Session) ValuesOf(ctx context.Context, any interface{}) (map[string]interface{}, error) { @@ -53,8 +54,9 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt hOptions := hstate.NewOptions(opts...) aState := stateType.Type().WithValue(dest) - var stateOptions []locator.Option - + var stateOptions = []locator.Option{ + locator.WithLogger(s.logger), + } var locatorsToRemove = []state.Kind{state.KindComponent} if hOptions.Constants() != nil { stateOptions = append(stateOptions, locator.WithConstants(hOptions.Constants())) From c91f5c207e9f218bdbbc6eb992458648a081bcb6 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 22 Aug 2025 13:57:38 -0700 Subject: [PATCH 007/117] patched logger nil --- service/operator/executor.go | 1 + 1 file changed, 1 insertion(+) diff --git a/service/operator/executor.go b/service/operator/executor.go index 53915c0ba..94d7fab94 100644 --- a/service/operator/executor.go +++ b/service/operator/executor.go @@ -26,6 +26,7 @@ func (s *Service) execute(ctx context.Context, aComponent *repository.Component, if aComponent.Handler != nil { aSession.SetView(aComponent.View) sessionHandler, err := anExecutor.NewHandlerSession(ctx, + handler.WithLogger(aSession.Logger()), handler.WithTypes(aComponent.Types()...), handler.WithAuth(aSession.Auth())) if err != nil { return nil, err From c0e2ca2aac83b07f7591e20f8bd98333e22425dd Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 25 Aug 2025 09:58:50 -0700 Subject: [PATCH 008/117] added race condition safeguard --- service/executor/expand/data_unit.go | 20 +++++++++++++------- view/predicate.go | 12 ++++++++---- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/service/executor/expand/data_unit.go b/service/executor/expand/data_unit.go index ac7d62452..8af4668aa 100644 --- a/service/executor/expand/data_unit.go +++ b/service/executor/expand/data_unit.go @@ -17,18 +17,18 @@ import ( type ( DataUnit struct { - Columns codec.ColumnsSource - ParamsGroup []interface{} - Mock bool - TemplateSQL string - MetaSource Dber `velty:"-"` - Statements *Statements `velty:"-"` - + Columns codec.ColumnsSource + ParamsGroup []interface{} + Mock bool + TemplateSQL string + MetaSource Dber `velty:"-"` + Statements *Statements `velty:"-"` mu sync.Mutex `velty:"-"` placeholderCounter int `velty:"-"` sqlxValidator *validator.Service `velty:"-"` sliceIndex map[reflect.Type]*xunsafe.Slice `velty:"-"` ctx context.Context `velty:"-"` + EvalLock sync.Mutex } ExecutablesIndex map[string]*Executable @@ -187,6 +187,12 @@ func (c *DataUnit) addAll(args ...interface{}) { c.mu.Unlock() } +func (c *DataUnit) Shrink(offset int) { + c.mu.Lock() + c.ParamsGroup = c.ParamsGroup[:offset] + c.mu.Unlock() +} + func (c *DataUnit) IsServiceExec(SQL string) (*Executable, bool) { return c.Statements.LookupExecutable(SQL) } diff --git a/view/predicate.go b/view/predicate.go index 69eb438f4..b7193fa94 100644 --- a/view/predicate.go +++ b/view/predicate.go @@ -3,6 +3,10 @@ package view import ( "context" "fmt" + "reflect" + "strings" + "sync" + expand "github.com/viant/datly/service/executor/expand" "github.com/viant/datly/utils/types" "github.com/viant/datly/view/extension" @@ -12,9 +16,6 @@ import ( "github.com/viant/xdatly/predicate" "github.com/viant/xreflect" "github.com/viant/xunsafe" - "reflect" - "strings" - "sync" ) type ( @@ -50,6 +51,9 @@ func (e *PredicateEvaluator) Compute(ctx context.Context, value interface{}) (*c panic("not found custom ctx") } + cuxtomCtx.DataUnit.EvalLock.Lock() + defer cuxtomCtx.DataUnit.EvalLock.Unlock() + val := ctx.Value(expand.PredicateState) aState := val.(*structology.State) offset := len(cuxtomCtx.DataUnit.ParamsGroup) @@ -64,7 +68,7 @@ func (e *PredicateEvaluator) Compute(ctx context.Context, value interface{}) (*c copy(values, evaluate.DataUnit.ParamsGroup[offset:]) } criteria := &codec.Criteria{Expression: evaluate.Buffer.String(), Placeholders: values} - cuxtomCtx.DataUnit.ParamsGroup = cuxtomCtx.DataUnit.ParamsGroup[:offset] + cuxtomCtx.DataUnit.Shrink(offset) return criteria, nil } From b8977dac36b85458e39b74f3021553bab884921f Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 25 Aug 2025 10:00:27 -0700 Subject: [PATCH 009/117] added race condition safeguard --- view/template.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/template.go b/view/template.go index c0b523b6c..92bed575c 100644 --- a/view/template.go +++ b/view/template.go @@ -372,7 +372,7 @@ func (t *Template) Expand(placeholders *[]interface{}, SQL string, selector *Sta if value.Key == "?" { placeholder, err := sanitized.Next() if err != nil { - return "", fmt.Errorf("failed to get placeholder: %w, SQL: %v, values: %v\n", err, SQL, values) + return "", fmt.Errorf("failed to get placeholder: %w, SQL: %v, values: %+v\n", err, SQL, values) } *placeholders = append(*placeholders, placeholder) From abfa80bfa68181b49b15ea73a23470ef14c87b1d Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 25 Aug 2025 17:09:30 -0700 Subject: [PATCH 010/117] added race condition safeguard --- service/executor/expand/data_unit.go | 11 ----------- service/executor/expand/state.go | 2 -- view/template.go | 1 - 3 files changed, 14 deletions(-) diff --git a/service/executor/expand/data_unit.go b/service/executor/expand/data_unit.go index 8af4668aa..89fea3f55 100644 --- a/service/executor/expand/data_unit.go +++ b/service/executor/expand/data_unit.go @@ -43,17 +43,6 @@ func (c *DataUnit) WithLocation(loc string) interface{} { return opt } -// Reset clears binding-related state so DataUnit can be safely reused for a new evaluation -func (c *DataUnit) Reset() { - c.mu.Lock() - c.placeholderCounter = 0 - if len(c.ParamsGroup) > 0 { - clear(c.ParamsGroup) - } - c.TemplateSQL = "" - c.mu.Unlock() -} - func (c *DataUnit) Validate(dest interface{}, opts ...interface{}) (*validator.Validation, error) { db, err := c.MetaSource.Db() if err != nil { diff --git a/service/executor/expand/state.go b/service/executor/expand/state.go index a69767fdb..1a6fffeb9 100644 --- a/service/executor/expand/state.go +++ b/service/executor/expand/state.go @@ -104,8 +104,6 @@ func (s *State) Init(templateState *est.State, predicates []*PredicateConfig, op if s.DataUnit == nil { s.DataUnit = NewDataUnit(nil) } - // Ensure bindings/cursor are reset for a fresh evaluation cycle - s.DataUnit.Reset() if s.Http == nil { s.Http = &Http{} diff --git a/view/template.go b/view/template.go index 92bed575c..e98ff37a2 100644 --- a/view/template.go +++ b/view/template.go @@ -373,7 +373,6 @@ func (t *Template) Expand(placeholders *[]interface{}, SQL string, selector *Sta placeholder, err := sanitized.Next() if err != nil { return "", fmt.Errorf("failed to get placeholder: %w, SQL: %v, values: %+v\n", err, SQL, values) - } *placeholders = append(*placeholders, placeholder) continue From 3b2abc8ba085dcb7373dc792466cb898d2e8f8a8 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 05:30:39 -0700 Subject: [PATCH 011/117] updated error handling --- go.mod | 2 +- go.sum | 2 ++ service/operator/reader.go | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 89bb2f2dd..c1a5bb6c7 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b github.com/viant/pgo v0.11.0 github.com/viant/scy v0.24.0 - github.com/viant/sqlx v0.17.6 + github.com/viant/sqlx v0.17.7 github.com/viant/structql v0.5.2 github.com/viant/toolbox v0.37.0 github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 diff --git a/go.sum b/go.sum index 5d442daa1..ccfd3ed70 100644 --- a/go.sum +++ b/go.sum @@ -1143,6 +1143,8 @@ github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= github.com/viant/sqlx v0.17.6 h1:6uMZVWk+WJl/y8coEh4F4mqbTHbtzWkLVEQdrk+m7sE= github.com/viant/sqlx v0.17.6/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= +github.com/viant/sqlx v0.17.7 h1:drUv3N8mOboq917gnmcT9zC4G9vj4jU11bO/SsLpmc8= +github.com/viant/sqlx v0.17.7/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= github.com/viant/structology v0.6.1/go.mod h1:63XfkzUyNw7wdi99HJIsH2Rg3d5AOumqbWLUYytOkxU= github.com/viant/structql v0.5.2 h1:0dAratszxC6AD/TNaV8BnLQQprNO5GJHaKjmszrIoeY= diff --git a/service/operator/reader.go b/service/operator/reader.go index bca67d847..e882d0643 100644 --- a/service/operator/reader.go +++ b/service/operator/reader.go @@ -23,6 +23,10 @@ func (s *Service) runQuery(ctx context.Context, component *repository.Component, defer func() { if r := recover(); r != nil { panicMsg := fmt.Sprintf("Panic occurred: %v, Stack trace: %v", r, string(debug.Stack())) + logger := aSession.Logger() + if logger == nil { + panic(panicMsg) + } aSession.Logger().Errorc(ctx, panicMsg) err = response.NewError(http.StatusInternalServerError, "Internal server error") output = nil From 3f8777cdea57812e7ecea6662eabf796c9ba71be Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 06:40:04 -0700 Subject: [PATCH 012/117] updated fs embeder handling --- view/resource.go | 14 +++++++++++++- view/state/parameter.go | 2 +- view/state/resource.go | 5 +++++ view/state/type.go | 4 ++++ view/tags/parser.go | 5 +++-- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/view/resource.go b/view/resource.go index 94ca4db9a..94cc59435 100644 --- a/view/resource.go +++ b/view/resource.go @@ -72,7 +72,8 @@ type ( Substitutes Substitutes Docs *Documentation - FSEmbedder *state.FSEmbedder + + FSEmbedder *state.FSEmbedder modTime time.Time _doc docs.Service @@ -152,6 +153,17 @@ func (r *Resource) ReverseSubstitutes(text string) string { return r.Substitutes.ReverseReplace(text) } +func (r *Resource) EmbedFS() *embed.FS { + if r.FSEmbedder == nil { + return nil + } + return r.FSEmbedder.EmbedFS() +} + +func (r *Resource) SetFSEmbedder(embedder *state.FSEmbedder) { + r.FSEmbedder = embedder +} + func (r *Resource) SetFs(fs afs.Service) { r.fs = fs } diff --git a/view/state/parameter.go b/view/state/parameter.go index ac6461b57..93670cd9f 100644 --- a/view/state/parameter.go +++ b/view/state/parameter.go @@ -523,7 +523,7 @@ func (p *Parameter) initCodec(resource Resource) error { if !p.Output.Schema.IsNamed() { fieldTag := reflect.StructTag(p.Tag) - if stateTag, _ := tags.ParseStateTags(fieldTag, nil); stateTag != nil { + if stateTag, _ := tags.ParseStateTags(fieldTag, resource.EmbedFS()); stateTag != nil { stateTag.TypeName = SanitizeTypeName(p.Output.Schema.Name) p.Tag = string(stateTag.UpdateTag(fieldTag)) } diff --git a/view/state/resource.go b/view/state/resource.go index 7c39ad857..b80f1fe1d 100644 --- a/view/state/resource.go +++ b/view/state/resource.go @@ -2,6 +2,7 @@ package state import ( "context" + "embed" "github.com/viant/xdatly/codec" "github.com/viant/xreflect" ) @@ -22,5 +23,9 @@ type ( ExpandSubstitutes(text string) string ReverseSubstitutes(text string) string + + EmbedFS() *embed.FS + + SetFSEmbedder(embedder *FSEmbedder) } ) diff --git a/view/state/type.go b/view/state/type.go index d64c07281..d2ea7c0c2 100644 --- a/view/state/type.go +++ b/view/state/type.go @@ -110,6 +110,10 @@ func (t *Type) ensureEmbedder(reflect.Type) { t.embedder = NewFSEmbedder(nil) } t.embedder.SetType(reflect.TypeOf(t)) + if t.resource != nil && t.resource.EmbedFS() == nil { + t.resource.SetFSEmbedder(t.embedder) + } + } func (t *Type) adjustConstants() { diff --git a/view/tags/parser.go b/view/tags/parser.go index aa4c407a0..283d1eded 100644 --- a/view/tags/parser.go +++ b/view/tags/parser.go @@ -4,14 +4,15 @@ import ( "context" "embed" "fmt" + "reflect" + "strings" + "github.com/viant/afs" "github.com/viant/afs/storage" "github.com/viant/afs/url" "github.com/viant/tagly/format" "github.com/viant/tagly/tags" "github.com/viant/xreflect" - "reflect" - "strings" ) // ValueTag represents default value tag From a7553f7d326fda119f462c6f358808d12ebcf9b3 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 10:03:27 -0700 Subject: [PATCH 013/117] updated fs embeder handling --- view/state/parameter.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/view/state/parameter.go b/view/state/parameter.go index 93670cd9f..a1ded9294 100644 --- a/view/state/parameter.go +++ b/view/state/parameter.go @@ -3,6 +3,11 @@ package state import ( "context" "fmt" + "net/http" + "reflect" + "strconv" + "strings" + "github.com/viant/datly/internal/setter" "github.com/viant/datly/shared" "github.com/viant/datly/utils/types" @@ -11,10 +16,6 @@ import ( "github.com/viant/structology" "github.com/viant/xreflect" "github.com/viant/xunsafe" - "net/http" - "reflect" - "strconv" - "strings" ) type ( @@ -512,7 +513,12 @@ func (p *Parameter) initCodec(resource Resource) error { if p.Output == nil { return nil } - + stateTag, _ := tags.ParseStateTags(reflect.StructTag(p.Tag), resource.EmbedFS()) + if stateTag != nil { + if stateTag.Codec != nil && stateTag.Codec.Body != "" { + p.Output.Body = stateTag.Codec.Body + } + } inputType := p.Schema.Type() if err := p.Output.Init(resource, inputType); err != nil { return err @@ -520,10 +526,9 @@ func (p *Parameter) initCodec(resource Resource) error { if p.Output.Schema == nil { return nil } - if !p.Output.Schema.IsNamed() { fieldTag := reflect.StructTag(p.Tag) - if stateTag, _ := tags.ParseStateTags(fieldTag, resource.EmbedFS()); stateTag != nil { + if stateTag != nil { stateTag.TypeName = SanitizeTypeName(p.Output.Schema.Name) p.Tag = string(stateTag.UpdateTag(fieldTag)) } From 5a9614b80d18324e92502037b54060b76ce1b76c Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 10:16:31 -0700 Subject: [PATCH 014/117] updated fs embeder handling --- service/executor/expand/predicate.go | 4 ++++ view/predicate.go | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/service/executor/expand/predicate.go b/service/executor/expand/predicate.go index b67e83312..292bb29c0 100644 --- a/service/executor/expand/predicate.go +++ b/service/executor/expand/predicate.go @@ -129,6 +129,10 @@ func (p *Predicate) expand(group int, operator string) (string, error) { } ctx = vcontext.WithValue(ctx, PredicateCtx, p.ctx) ctx = vcontext.WithValue(ctx, PredicateState, p.state) + + p.ctx.DataUnit.EvalLock.Lock() + defer p.ctx.DataUnit.EvalLock.Unlock() + if p.ctx.Session != nil { aLogger := p.ctx.Session.Logger() ctx = vcontext.WithValue(ctx, logger.ContextKey, aLogger) diff --git a/view/predicate.go b/view/predicate.go index b7193fa94..189e656aa 100644 --- a/view/predicate.go +++ b/view/predicate.go @@ -51,9 +51,6 @@ func (e *PredicateEvaluator) Compute(ctx context.Context, value interface{}) (*c panic("not found custom ctx") } - cuxtomCtx.DataUnit.EvalLock.Lock() - defer cuxtomCtx.DataUnit.EvalLock.Unlock() - val := ctx.Value(expand.PredicateState) aState := val.(*structology.State) offset := len(cuxtomCtx.DataUnit.ParamsGroup) From 1325f81749e688218ef173849eeff67ff6d0410c Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 12:33:17 -0700 Subject: [PATCH 015/117] updated fs embeder handling --- go.sum | 2 -- service/executor/expand/evaluator.go | 3 ++- service/session/stater.go | 8 +++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/go.sum b/go.sum index ccfd3ed70..9eda4cc46 100644 --- a/go.sum +++ b/go.sum @@ -1141,8 +1141,6 @@ github.com/viant/scy v0.24.0 h1:KAC3IUARkQxTNSuwBK2YhVBJMOOLN30YaLKHbbuSkMU= github.com/viant/scy v0.24.0/go.mod h1:7uNRS67X45YN+JqTLCcMEhehffVjqrejULEDln9p0Ao= github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns= github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= -github.com/viant/sqlx v0.17.6 h1:6uMZVWk+WJl/y8coEh4F4mqbTHbtzWkLVEQdrk+m7sE= -github.com/viant/sqlx v0.17.6/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/sqlx v0.17.7 h1:drUv3N8mOboq917gnmcT9zC4G9vj4jU11bO/SsLpmc8= github.com/viant/sqlx v0.17.7/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= diff --git a/service/executor/expand/evaluator.go b/service/executor/expand/evaluator.go index d57b935b2..3b14cf832 100644 --- a/service/executor/expand/evaluator.go +++ b/service/executor/expand/evaluator.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "reflect" + "github.com/viant/datly/view/keywords" "github.com/viant/datly/view/state/predicate" "github.com/viant/godiff" @@ -12,7 +14,6 @@ import ( "github.com/viant/velty/est" "github.com/viant/velty/est/op" "github.com/viant/xreflect" - "reflect" ) type ( diff --git a/service/session/stater.go b/service/session/stater.go index ed50be0b3..c2d4555b5 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -116,10 +116,12 @@ func (s *Session) handleComponentpOutputType(ctx context.Context, dest interface destValue, err := s.operate(ctx, s, s.component) s.Options = sessionOpt - if destValue != nil { - reflect.ValueOf(dest).Elem().Set(reflect.ValueOf(destValue).Elem()) + reflectDestValue := reflect.ValueOf(destValue) + if reflectDestValue.Kind() == reflect.Ptr { + reflect.ValueOf(dest).Elem().Set(reflectDestValue.Elem()) + } else { + reflect.ValueOf(dest).Elem().Set(reflectDestValue) } - if err != nil { return err } From 09d33d3d0fbadca33321499edd3a7dd91633e246 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 12:44:38 -0700 Subject: [PATCH 016/117] updated fs embeder handling --- service/session/stater.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/service/session/stater.go b/service/session/stater.go index c2d4555b5..f50f63cfb 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -2,11 +2,15 @@ package session import ( "context" + "fmt" + "net/http" "reflect" + "runtime/debug" "github.com/viant/datly/utils/types" "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind/locator" + "github.com/viant/xdatly/handler/response" hstate "github.com/viant/xdatly/handler/state" ) @@ -36,6 +40,18 @@ func (s *Session) Into(ctx context.Context, dest interface{}, opts ...hstate.Opt } func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Option) (err error) { + defer func() { + if r := recover(); r != nil { + panicMsg := fmt.Sprintf("Panic occurred: %v, Stack trace: %v", r, string(debug.Stack())) + logger := s.Logger() + if logger == nil { + panic(panicMsg) + } + s.Logger().Errorc(ctx, panicMsg) + err = response.NewError(http.StatusInternalServerError, "Internal server error") + } + }() + destType := reflect.TypeOf(dest) sType := types.EnsureStruct(destType) stateType, ok := s.Types.Lookup(sType) From 8de645caaad7a89df8f0887893c671368e11aacc Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 12:45:43 -0700 Subject: [PATCH 017/117] updated fs embeder handling --- service/session/stater.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service/session/stater.go b/service/session/stater.go index f50f63cfb..3530b912e 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -133,10 +133,11 @@ func (s *Session) handleComponentpOutputType(ctx context.Context, dest interface s.Options = sessionOpt reflectDestValue := reflect.ValueOf(destValue) + destPtr := reflect.ValueOf(dest) if reflectDestValue.Kind() == reflect.Ptr { - reflect.ValueOf(dest).Elem().Set(reflectDestValue.Elem()) + destPtr.Elem().Set(reflectDestValue.Elem()) } else { - reflect.ValueOf(dest).Elem().Set(reflectDestValue) + destPtr.Elem().Set(reflectDestValue) } if err != nil { return err From e6519bec30ba5619bebaf883905b98ac5e27a39a Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 26 Aug 2025 13:01:58 -0700 Subject: [PATCH 018/117] updated fs embeder handling --- service/session/stater.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/service/session/stater.go b/service/session/stater.go index 3530b912e..d2bda7a34 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -130,17 +130,21 @@ func (s *Session) handleComponentpOutputType(ctx context.Context, dest interface sessionOpt := s.Options s.Options = *s.Indirect(true, stateOptions...) destValue, err := s.operate(ctx, s, s.component) + destPtr := reflect.ValueOf(dest) + if err != nil && destValue == nil { + if errorSetter, ok := dest.(response.StatusSetter); ok { + errorSetter.SetError(err) + return nil + } + return err + } s.Options = sessionOpt - reflectDestValue := reflect.ValueOf(destValue) - destPtr := reflect.ValueOf(dest) + if reflectDestValue.Kind() == reflect.Ptr { destPtr.Elem().Set(reflectDestValue.Elem()) } else { destPtr.Elem().Set(reflectDestValue) } - if err != nil { - return err - } return nil } From 3c912377621f1100270130b6099329838cdf57dd Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 27 Aug 2025 20:35:27 -0700 Subject: [PATCH 019/117] patched predicate racing --- service/executor/expand/data_unit.go | 2 ++ service/reader/sql.go | 6 ++++-- view/predicate.go | 23 +++++++++++++++-------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/service/executor/expand/data_unit.go b/service/executor/expand/data_unit.go index 89fea3f55..ad8516e76 100644 --- a/service/executor/expand/data_unit.go +++ b/service/executor/expand/data_unit.go @@ -34,6 +34,8 @@ type ( ExecutablesIndex map[string]*Executable ) +// + func (c *DataUnit) WithPresence() interface{} { var opt interface{} = validator.WithSetMarker() return opt diff --git a/service/reader/sql.go b/service/reader/sql.go index 33d7747ca..5e3ac5b35 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -3,14 +3,15 @@ package reader import ( "context" "fmt" + "strconv" + "strings" + "github.com/viant/datly/service/executor/expand" "github.com/viant/datly/service/reader/metadata" "github.com/viant/datly/shared" "github.com/viant/datly/view" "github.com/viant/datly/view/keywords" "github.com/viant/sqlx/io/read/cache" - "strconv" - "strings" ) const ( @@ -50,6 +51,7 @@ func (b *Builder) Build(ctx context.Context, opts ...BuilderOption) (*cache.Parm parent := options.parent partitions := options.partition expander := options.expander + state, err := aView.Template.EvaluateSource(ctx, statelet.Template, parent, &batchData, expander) if err != nil { diff --git a/view/predicate.go b/view/predicate.go index 189e656aa..d6e5b3820 100644 --- a/view/predicate.go +++ b/view/predicate.go @@ -53,19 +53,26 @@ func (e *PredicateEvaluator) Compute(ctx context.Context, value interface{}) (*c val := ctx.Value(expand.PredicateState) aState := val.(*structology.State) - offset := len(cuxtomCtx.DataUnit.ParamsGroup) - evaluate, err := e.Evaluate(cuxtomCtx, aState, value) + // evaluate predicate with an isolated DataUnit to avoid + // mutating parent DataUnit and relying on Shrink/restore across nesting. + var metaSource expand.Dber + if cuxtomCtx.DataUnit != nil { + metaSource = cuxtomCtx.DataUnit.MetaSource + } + isolatedDU := expand.NewDataUnit(metaSource) + tmpCtx := *cuxtomCtx + tmpCtx.DataUnit = isolatedDU + + evaluate, err := e.Evaluate(&tmpCtx, aState, value) if err != nil { return nil, err } - placeholderLen := len(evaluate.DataUnit.ParamsGroup) - offset - var values = make([]interface{}, placeholderLen) - if placeholderLen > 0 { - copy(values, evaluate.DataUnit.ParamsGroup[offset:]) - } + // Collect placeholders from the isolated DataUnit and return them + // to the caller; do not mutate the parent DataUnit here. + values := make([]interface{}, len(isolatedDU.ParamsGroup)) + copy(values, isolatedDU.ParamsGroup) criteria := &codec.Criteria{Expression: evaluate.Buffer.String(), Placeholders: values} - cuxtomCtx.DataUnit.Shrink(offset) return criteria, nil } From 1ed2fee050a9b215999fc2692de8f276fef8c85f Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 29 Aug 2025 07:20:42 -0700 Subject: [PATCH 020/117] updated limit --- internal/inference/parameter.go | 11 ++++++----- repository/component.go | 10 +++++++--- view/view.go | 15 ++++++++++----- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/internal/inference/parameter.go b/internal/inference/parameter.go index d3403859f..30b3e6893 100644 --- a/internal/inference/parameter.go +++ b/internal/inference/parameter.go @@ -4,6 +4,12 @@ import ( "embed" _ "embed" "fmt" + "go/ast" + "path" + "reflect" + "strconv" + "strings" + "github.com/viant/datly/view" "github.com/viant/datly/view/state" "github.com/viant/datly/view/tags" @@ -15,11 +21,6 @@ import ( "github.com/viant/tagly/format/text" "github.com/viant/xreflect" "github.com/viant/xunsafe" - "go/ast" - "path" - "reflect" - "strconv" - "strings" ) type ( diff --git a/repository/component.go b/repository/component.go index 31faed6cf..112f6ff7d 100644 --- a/repository/component.go +++ b/repository/component.go @@ -4,6 +4,10 @@ import ( "context" "embed" "fmt" + "net/http" + "reflect" + "strings" + "github.com/francoispqt/gojay" "github.com/viant/afs" "github.com/viant/datly/gateway/router/marshal" @@ -29,9 +33,6 @@ import ( xhandler "github.com/viant/xdatly/handler" hstate "github.com/viant/xdatly/handler/state" "github.com/viant/xreflect" - "net/http" - "reflect" - "strings" ) // Component represents abstract API view/handler based component @@ -424,6 +425,9 @@ func WithContract(inputType, outputType reflect.Type, embedFs *embed.FS, viewOpt aCache := &view.Cache{Reference: shared.Reference{Ref: aView.Cache}} viewOptions = append(viewOptions, view.WithCache(aCache)) } + if aView.Limit != nil { + viewOptions = append(viewOptions, view.WithLimit(aView.Limit)) + } if aTag.View.PublishParent { viewOptions = append(viewOptions, view.WithViewPublishParent(aTag.View.PublishParent)) diff --git a/view/view.go b/view/view.go index 42bcc1906..8226a9cd2 100644 --- a/view/view.go +++ b/view/view.go @@ -4,6 +4,12 @@ import ( "context" "database/sql" "fmt" + "net/http" + "path" + "reflect" + "strings" + "time" + "github.com/viant/afs/url" "github.com/viant/datly/gateway/router/marshal" "github.com/viant/datly/internal/setter" @@ -23,11 +29,6 @@ import ( "github.com/viant/tagly/format/text" "github.com/viant/xreflect" "github.com/viant/xunsafe" - "net/http" - "path" - "reflect" - "strings" - "time" ) const ( @@ -400,6 +401,10 @@ func (v *View) inheritRelationsFromTag(schema *state.Schema) error { refViewOptions = append(refViewOptions, WithCache(aCache)) } + if viewTag.Limit != nil { + viewOptions = append(viewOptions, WithLimit(viewTag.Limit)) + } + if viewTag.PublishParent { refViewOptions = append(refViewOptions, WithViewPublishParent(viewTag.PublishParent)) } From 1d3e0a271d6465128932b6f42bd7b227b0981b37 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 29 Aug 2025 09:30:01 -0700 Subject: [PATCH 021/117] updated limit --- view/view.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/view/view.go b/view/view.go index 8226a9cd2..d2f3bf567 100644 --- a/view/view.go +++ b/view/view.go @@ -478,6 +478,9 @@ func WithLimit(limit *int) Option { } view.Selector.Constraints.Limit = true view.Selector.Limit = *limit + if limit != nil { + view.Selector.NoLimit = *limit == 0 + } return nil } } From 17b3e4507af0740bd0e84b71f148875c2d5cc9cf Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 29 Aug 2025 10:51:55 -0700 Subject: [PATCH 022/117] patched limit --- internal/codegen/handler.go | 3 ++- internal/inference/parameter.go | 8 ++++++++ internal/translator/parser/declarations.go | 11 ++++++++--- internal/translator/resource.go | 16 +++++++++++++--- internal/translator/service.go | 2 +- repository/component.go | 4 ++++ 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/internal/codegen/handler.go b/internal/codegen/handler.go index 5c732a16e..dafbd99a8 100644 --- a/internal/codegen/handler.go +++ b/internal/codegen/handler.go @@ -2,11 +2,12 @@ package codegen import ( _ "embed" + "strings" + "github.com/viant/datly/cmd/options" "github.com/viant/datly/internal/codegen/ast" "github.com/viant/datly/internal/inference" "github.com/viant/datly/internal/plugin" - "strings" ) //go:embed tmpl/handler/handler.gox diff --git a/internal/inference/parameter.go b/internal/inference/parameter.go index 30b3e6893..eddb8efe5 100644 --- a/internal/inference/parameter.go +++ b/internal/inference/parameter.go @@ -35,6 +35,7 @@ type ( AssumedType bool Connector string Cache string + Limit *int InOutput bool Of string } @@ -116,6 +117,10 @@ func (p *Parameter) veltyDeclaration(builder *strings.Builder) { builder.WriteString(".WithCache('" + p.Cache + "')") } + if p.Limit != nil { + builder.WriteString(".WithLimit('" + strconv.Itoa(*p.Limit) + "')") + } + if p.Required != nil { if !*p.Required { builder.WriteString(".Optional()") @@ -305,6 +310,9 @@ func buildParameter(field *xunsafe.Field, aTag *tags.Tag, types *xreflect.Types, if aTag.View.Cache != "" { param.Cache = aTag.View.Cache } + if aTag.View.Limit != nil { + param.Limit = aTag.View.Limit + } } fType := field.Type diff --git a/internal/translator/parser/declarations.go b/internal/translator/parser/declarations.go index ca11710de..d5113539e 100644 --- a/internal/translator/parser/declarations.go +++ b/internal/translator/parser/declarations.go @@ -2,6 +2,10 @@ package parser import ( "fmt" + "reflect" + "strconv" + "strings" + "github.com/viant/datly/gateway/router/marshal" "github.com/viant/datly/internal/inference" "github.com/viant/datly/shared" @@ -12,9 +16,6 @@ import ( "github.com/viant/velty/ast/expr" "github.com/viant/velty/parser" "github.com/viant/xreflect" - "reflect" - "strconv" - "strings" ) type ( @@ -322,6 +323,10 @@ func (s *Declarations) parseShorthands(declaration *Declaration, cursor *parsly. declaration.InOutput = true case "WithCache": declaration.Cache = strings.Trim(args[0], `"'`) + case "WithLimit": + limit, _ := strconv.Atoi(strings.Trim(args[0], `"'`)) + declaration.Limit = &limit + case "Cacheable": literal := strings.Trim(args[0], `"'`) value, _ := strconv.ParseBool(literal) diff --git a/internal/translator/resource.go b/internal/translator/resource.go index eb92605b8..163684277 100644 --- a/internal/translator/resource.go +++ b/internal/translator/resource.go @@ -3,6 +3,10 @@ package translator import ( "context" "fmt" + "path" + "reflect" + "strings" + "github.com/viant/afs" "github.com/viant/afs/url" "github.com/viant/datly/cmd/options" @@ -22,9 +26,6 @@ import ( "github.com/viant/toolbox" "github.com/viant/xreflect" "golang.org/x/mod/modfile" - "path" - "reflect" - "strings" ) type ( @@ -352,6 +353,15 @@ func (r *Resource) buildParameterViews() { if parameter.Cache != "" { viewlet.View.Cache = &view.Cache{Reference: shared.Reference{Ref: parameter.Cache}} } + if parameter.Limit != nil { + if viewlet.View.Selector == nil { + viewlet.View.Selector = &view.Config{ + Constraints: &view.Constraints{Limit: true}, + } + } + viewlet.View.Selector.Limit = *parameter.Limit + viewlet.View.Selector.NoLimit = viewlet.View.Selector.Limit == 0 + } if viewlet.Connector == "" { viewlet.Connector = r.rootConnector } diff --git a/internal/translator/service.go b/internal/translator/service.go index d53f4e6a3..70e71d683 100644 --- a/internal/translator/service.go +++ b/internal/translator/service.go @@ -20,7 +20,7 @@ import ( "github.com/viant/datly/internal/plugin" "github.com/viant/datly/internal/setter" "github.com/viant/datly/internal/translator/parser" - signature "github.com/viant/datly/repository/contract/signature" + "github.com/viant/datly/repository/contract/signature" "github.com/viant/datly/repository/path" "github.com/viant/datly/service" "github.com/viant/datly/shared" diff --git a/repository/component.go b/repository/component.go index 112f6ff7d..109ded23a 100644 --- a/repository/component.go +++ b/repository/component.go @@ -445,6 +445,10 @@ func WithContract(inputType, outputType reflect.Type, embedFs *embed.FS, viewOpt if aTag.View.Batch != 0 { viewOptions = append(viewOptions, view.WithBatchSize(aTag.View.Batch)) } + if aTag.View.Limit != nil { + viewOptions = append(viewOptions, view.WithLimit(aTag.View.Limit)) + } + if aTag.View.RelationalConcurrency != 0 { viewOptions = append(viewOptions, view.WithRelationalConcurrency(aTag.View.RelationalConcurrency)) } From 09ce111ae2213c67699dc5cddaf369b1f4220f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Filipowicz?= Date: Wed, 3 Sep 2025 14:09:09 +0200 Subject: [PATCH 023/117] updated ensureValidValue --- service/session/state.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/service/session/state.go b/service/session/state.go index 7fcfb5c70..f7b0e8ce5 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -347,10 +347,17 @@ func (s *Session) ensureValidValue(value interface{}, parameter *state.Parameter if valueType.Elem().Kind() == reflect.Struct && parameter.Schema.Type().Kind() == reflect.Slice { if parameter.Schema.CompType() == valueType { sliceValuePtr := reflect.New(parameterType) + + if isNil(value) { + empty := reflect.MakeSlice(parameterType, 0, 0) + sliceValuePtr.Elem().Set(empty) + return sliceValuePtr.Interface(), nil // []T{} + } + sliceValue := reflect.MakeSlice(parameterType, 1, 1) sliceValuePtr.Elem().Set(sliceValue) sliceValue.Index(0).Set(reflect.ValueOf(value)) - return sliceValuePtr.Interface(), nil + return sliceValuePtr.Interface(), nil // []T{value}` } } case reflect.Slice: From d51933a38e1e11714ea046be309f6dba9339610b Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 5 Sep 2025 14:29:33 -0700 Subject: [PATCH 024/117] updated error handling --- service/reader/sql.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/service/reader/sql.go b/service/reader/sql.go index 5e3ac5b35..58598ed12 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -57,6 +57,12 @@ func (b *Builder) Build(ctx context.Context, opts ...BuilderOption) (*cache.Parm if err != nil { return nil, err } + if state == nil { + return nil, fmt.Errorf("failed to evaluate state for view %v, state was nil", aView.Name) + } + if state.Expanded == "" { + return nil, fmt.Errorf("failed to evaluate expanded for view %vm statelet was nil", aView.Name) + } if len(state.Filters) > 0 { statelet.Filters = append(statelet.Filters, state.Filters...) } From fda81402bd1914fdc786aec2faab8dcb5c3d5426 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 5 Sep 2025 15:23:59 -0700 Subject: [PATCH 025/117] updated error handling --- service/reader/sql.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/service/reader/sql.go b/service/reader/sql.go index 58598ed12..7cc1f6fa1 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -45,13 +45,23 @@ func (b *Builder) Build(ctx context.Context, opts ...BuilderOption) (*cache.Parm options := newBuilderOptions(opts...) aView := options.view statelet := options.statelet - batchData := *options.batchData + // guard against nil batchData passed by callers + var batchData view.BatchData + if options.batchData != nil { + batchData = *options.batchData + } relation := options.relation exclude := options.exclude parent := options.parent partitions := options.partition expander := options.expander + // ensure non-nil statelet to avoid nil deref on Template usage + if statelet == nil { + statelet = view.NewStatelet() + statelet.Init(aView) + } + state, err := aView.Template.EvaluateSource(ctx, statelet.Template, parent, &batchData, expander) if err != nil { From c0f5411ef1cf0bd7607d15df6733478a0c0f3e1a Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 5 Sep 2025 16:27:03 -0700 Subject: [PATCH 026/117] updated error handling --- service/reader/sql.go | 2 +- view/state.go | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/service/reader/sql.go b/service/reader/sql.go index 7cc1f6fa1..bcb7aff93 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -74,7 +74,7 @@ func (b *Builder) Build(ctx context.Context, opts ...BuilderOption) (*cache.Parm return nil, fmt.Errorf("failed to evaluate expanded for view %vm statelet was nil", aView.Name) } if len(state.Filters) > 0 { - statelet.Filters = append(statelet.Filters, state.Filters...) + statelet.AppendFilters(state.Filters) } if aView.Template.IsActualTemplate() && aView.ShouldTryDiscover() { state.Expanded = metadata.EnrichWithDiscover(state.Expanded, true) diff --git a/view/state.go b/view/state.go index 3484de7f8..a7ff10ece 100644 --- a/view/state.go +++ b/view/state.go @@ -44,6 +44,7 @@ type ( initialized bool _columnNames map[string]bool result *cache.ParmetrizedQuery + filtersMu sync.Mutex } ) @@ -99,6 +100,16 @@ func (s *QuerySelector) SetCriteria(expanded string, placeholders []interface{}) s.Placeholders = placeholders } +// AppendFilters safely appends filters to the selector's Filters to avoid data races. +func (s *Statelet) AppendFilters(filters predicate.Filters) { + if len(filters) == 0 { + return + } + s.QuerySelector.filtersMu.Lock() + s.QuerySelector.Filters = append(s.QuerySelector.Filters, filters...) + s.QuerySelector.filtersMu.Unlock() +} + // NewStatelet creates a selector func NewStatelet() *Statelet { return &Statelet{ From 310295e0edd66d82cdfa1d80ff81b44e658ae364 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 8 Sep 2025 14:11:24 -0700 Subject: [PATCH 027/117] updated error handling --- service/executor/expand/evaluator.go | 2 +- service/executor/expand/predicate.go | 6 +++++- service/executor/expand/state.go | 6 +++--- view/predicate.go | 13 ++++++++++++- view/template.go | 4 ++++ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/service/executor/expand/evaluator.go b/service/executor/expand/evaluator.go index 3b14cf832..f898b4ffa 100644 --- a/service/executor/expand/evaluator.go +++ b/service/executor/expand/evaluator.go @@ -253,7 +253,7 @@ func (e *Evaluator) ensureState(ctx *Context, options ...StateOption) *State { state.Context = ctx } - state.Init(e.stateProvider(), e.predicateConfigs, options...) + state.Init(e.stateProvider(), e.predicateConfigs, e.stateType, options...) return state } diff --git a/service/executor/expand/predicate.go b/service/executor/expand/predicate.go index 292bb29c0..aae51c8bb 100644 --- a/service/executor/expand/predicate.go +++ b/service/executor/expand/predicate.go @@ -38,7 +38,11 @@ type ( } ) -func NewPredicate(ctx *Context, state *structology.State, config []*PredicateConfig) *Predicate { +func NewPredicate(ctx *Context, state *structology.State, config []*PredicateConfig, stateType *structology.StateType) *Predicate { + // Initialize state if not provided, but never override an existing state + if state == nil && stateType != nil { + state = stateType.NewState() + } return &Predicate{ ctx: ctx, config: config, diff --git a/service/executor/expand/state.go b/service/executor/expand/state.go index 1a6fffeb9..6399be43d 100644 --- a/service/executor/expand/state.go +++ b/service/executor/expand/state.go @@ -84,7 +84,7 @@ func WithCustomContext(customContext *Variable) StateOption { } } -func (s *State) Init(templateState *est.State, predicates []*PredicateConfig, options ...StateOption) { +func (s *State) Init(templateState *est.State, predicates []*PredicateConfig, stateType *structology.StateType, options ...StateOption) { for _, option := range options { option(s) } @@ -121,7 +121,7 @@ func (s *State) Init(templateState *est.State, predicates []*PredicateConfig, op s.MessageBus = s.Session.MessageBus() } - s.Predicate = NewPredicate(s.Context, s.ParametersState, predicates) + s.Predicate = NewPredicate(s.Context, s.ParametersState, predicates, stateType) s.State = templateState } @@ -148,6 +148,6 @@ func StateWithSQL(ctx context.Context, SQL string) *State { Context: &Context{Context: ctx}, } - aState.Init(nil, nil) + aState.Init(nil, nil, nil) return aState } diff --git a/view/predicate.go b/view/predicate.go index d6e5b3820..415550c28 100644 --- a/view/predicate.go +++ b/view/predicate.go @@ -35,6 +35,7 @@ type ( state *expand.NamedVariable hasStateName *expand.NamedVariable handler codec.PredicateHandler + stateType *structology.StateType } PredicateEvaluator struct { @@ -42,6 +43,7 @@ type ( evaluator *expand.Evaluator valueState *expand.NamedVariable hasValueState *expand.NamedVariable + stateType *structology.StateType } ) @@ -52,7 +54,14 @@ func (e *PredicateEvaluator) Compute(ctx context.Context, value interface{}) (*c } val := ctx.Value(expand.PredicateState) - aState := val.(*structology.State) + var aState *structology.State + if s, ok := val.(*structology.State); ok { + aState = s + } + if aState == nil && e.stateType != nil { + // Initialize state if absent; do not override if provided. + aState = e.stateType.NewState() + } // evaluate predicate with an isolated DataUnit to avoid // mutating parent DataUnit and relying on Shrink/restore across nesting. var metaSource expand.Dber @@ -158,6 +167,7 @@ func (p *predicateEvaluatorProvider) new(predicateConfig *extension.PredicateCon evaluator: p.evaluator, valueState: p.state, hasValueState: p.hasStateName, + stateType: p.stateType, }, nil } @@ -215,5 +225,6 @@ func (p *predicateEvaluatorProvider) init(resource *Resource, predicateConfig *e p.signature = argsIndexed p.state = stateVariable p.hasStateName = hasVariable + p.stateType = stateType return nil } diff --git a/view/template.go b/view/template.go index e98ff37a2..ae4308723 100644 --- a/view/template.go +++ b/view/template.go @@ -231,6 +231,10 @@ func (t *Template) EvaluateState(ctx context.Context, parameterState *structolog } func (t *Template) EvaluateStateWithSession(ctx context.Context, parameterState *structology.State, parentParam *expand.ViewContext, batchData *BatchData, sess *extension.Session, options ...interface{}) (*expand.State, error) { + // Ensure parameter state is initialized when absent, but never override an existing one. + if parameterState == nil && t.stateType != nil { + parameterState = t.stateType.NewState() + } var expander expand.Expander var dataUnit *expand.DataUnit for _, option := range options { From e95c4d7311b92217ef43957001b949ea4e6c008e Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 8 Sep 2025 14:18:55 -0700 Subject: [PATCH 028/117] updated error handling --- repository/logging/logging.go | 4 ++-- service/reader/handler/handler.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/repository/logging/logging.go b/repository/logging/logging.go index 2383e2f11..c0054ea70 100644 --- a/repository/logging/logging.go +++ b/repository/logging/logging.go @@ -15,7 +15,7 @@ func Log(config *Config, execContext *exec.Context) { execContext.Metrics = execContext.Metrics.HideMetrics() } if config.IsAuditEnabled() { - data, _ := json.Marshal(execContext) + data, _ := json.MarshalNoEscape(execContext) fmt.Println("[AUDIT] " + string(data)) } if config.IsTracingEnabled() { @@ -42,7 +42,7 @@ func Log(config *Config, execContext *exec.Context) { } else { trace.Spans[0].SetStatusFromHTTPCode(execContext.StatusCode) } - traceData, _ := json.Marshal(trace) + traceData, _ := json.MarshalNoEscape(trace) fmt.Println("[TRACE] " + string(traceData)) } } diff --git a/service/reader/handler/handler.go b/service/reader/handler/handler.go index c3a485dc1..f85797711 100644 --- a/service/reader/handler/handler.go +++ b/service/reader/handler/handler.go @@ -139,7 +139,7 @@ func (h *Handler) publishViewSummaryIfNeeded(aView *view.View, ret *Response) { if templateMeta.Kind != view.MetaKindHeader { return } - data, err := goJson.Marshal(ret.Reader.DataSummary) + data, err := goJson.MarshalNoEscape(ret.Reader.DataSummary) if err != nil { ret.StatusCode = http.StatusInternalServerError ret.Status.Status = "error" @@ -157,7 +157,7 @@ func (h *Handler) publishMetricsIfNeeded(aSession *reader.Session, ret *Response if info.Executions == nil { continue } - data, err := goJson.Marshal(info) + data, err := goJson.MarshalNoEscape(info) if err != nil { continue } From c672e99e1072a4c845b4e65ac94ab4a5c6a1eab3 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 15 Sep 2025 11:23:01 -0700 Subject: [PATCH 029/117] updated dep --- go.mod | 7 +++---- go.sum | 14 ++++++-------- internal/translator/viewlets.go | 3 +++ mcp/server.go | 15 ++++++++------ service/executor/expand/data_unit.go | 11 +++++++++++ view/extension/init.go | 9 ++++++--- view/extension/predicates.go | 29 +++++++++++++++++++++++++++- view/tags/codec.go | 9 +++++---- view/tags/predicate.go | 8 +++++--- 9 files changed, 76 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index c1a5bb6c7..51eacc09c 100644 --- a/go.mod +++ b/go.mod @@ -49,9 +49,9 @@ require ( require ( github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d github.com/viant/firebase v0.1.1 - github.com/viant/jsonrpc v0.7.2 - github.com/viant/mcp v0.4.3 - github.com/viant/mcp-protocol v0.4.4 + github.com/viant/jsonrpc v0.7.5 + github.com/viant/mcp v0.5.2 + github.com/viant/mcp-protocol v0.5.7 github.com/viant/structology v0.6.1 github.com/viant/tagly v0.2.2 github.com/viant/xdatly v0.5.4-0.20250806192028-819cadf93282 @@ -106,7 +106,6 @@ require ( github.com/go-errors/errors v1.5.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/go.sum b/go.sum index 9eda4cc46..9508d64ec 100644 --- a/go.sum +++ b/go.sum @@ -786,8 +786,6 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= @@ -1127,12 +1125,12 @@ github.com/viant/govalidator v0.3.1 h1:V7f/KgfzbP8fVDc+Kj+jyPvfXxMr2N1x7srOlDV6l github.com/viant/govalidator v0.3.1/go.mod h1:D35Dwx0R8rR1knRxhlseoYvOkiqo24kpMg1/o977i9Y= github.com/viant/igo v0.2.0 h1:ygWmTCinnGPaeV7omJLiyneOpzYZ5kiw7oYz7mUJZVQ= github.com/viant/igo v0.2.0/go.mod h1:7V6AWsLhKWeGzXNTNH3AZiIEKa0m33DrQbdWtapsI74= -github.com/viant/jsonrpc v0.7.2 h1:FUzhfFN76E09ZbQOxReFOyPhsxYhE0fjWzPhattR9Dk= -github.com/viant/jsonrpc v0.7.2/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= -github.com/viant/mcp v0.4.3 h1:ykQ2XyS2l5xrxHY5peJgIWoH+n8ZSpiSifnO/UH6/3I= -github.com/viant/mcp v0.4.3/go.mod h1:3SnILtYVIT8PIWICMyzP9KfhepawoFRv+//FBU/hc7c= -github.com/viant/mcp-protocol v0.4.4 h1:jKuCHvXeNof1Of1UfUyJkrSSNfOBiN4pXKWv3J2NwFM= -github.com/viant/mcp-protocol v0.4.4/go.mod h1:EL4NY7yW2gge+XLorgJA7PIazQX3x4ZkutYihwBwINs= +github.com/viant/jsonrpc v0.7.5 h1:QiLEVl5nP7j5i55jDQp4HUURKJLf+ENPafTlJT13u38= +github.com/viant/jsonrpc v0.7.5/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= +github.com/viant/mcp v0.5.2 h1:m0Z7LdYOQOs7MhYg7Ql9nZlJDiedHfC86VNRzfKg3Gs= +github.com/viant/mcp v0.5.2/go.mod h1:ybylH9mD3/aVLrT8KQsakmsKxtfw7Kpo4A9hmTuetGw= +github.com/viant/mcp-protocol v0.5.7 h1:3ifypMAy+oUjQEAsq+XwrAhE/B/3eIes4yXdhoRF9Eo= +github.com/viant/mcp-protocol v0.5.7/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b/go.mod h1:85fneXJbErKMGhSQto3A5ElTQCwl3t74U9cSV0waBHw= github.com/viant/pgo v0.11.0 h1:PNuYVhwTfyrAHGBO6lxaMFuHP4NkjKV8ULecz3OWk8c= diff --git a/internal/translator/viewlets.go b/internal/translator/viewlets.go index eb1d24b7b..72707387c 100644 --- a/internal/translator/viewlets.go +++ b/internal/translator/viewlets.go @@ -138,6 +138,9 @@ func (n *Viewlets) addRelations(query *query.Select) error { parentNs := inference.ParentAlias(join) parentViewlet := n.Lookup(parentNs) + if parentViewlet == nil { + return fmt.Errorf("parent viewlet %v doesn't exist", parentNs) + } relation.Spec.Parent = parentViewlet.Spec cardinality := state.Many if inference.IsToOne(join) || relation.OutputSettings.IsToOne() { diff --git a/mcp/server.go b/mcp/server.go index 2c9cd306e..2409a38ea 100644 --- a/mcp/server.go +++ b/mcp/server.go @@ -3,6 +3,7 @@ package mcp import ( "context" "fmt" + "github.com/viant/afs" "github.com/viant/afs/http" "github.com/viant/afs/url" @@ -15,18 +16,20 @@ import ( "github.com/viant/mcp/client/auth/transport" authserver "github.com/viant/mcp/server/auth" - serverproto "github.com/viant/mcp-protocol/server" - "github.com/viant/scy/auth/flow" "os" "path" + serverproto "github.com/viant/mcp-protocol/server" + "github.com/viant/scy/auth/flow" + + "reflect" + "strconv" + "strings" + "github.com/viant/mcp/server" "github.com/viant/scy" "github.com/viant/scy/cred" "golang.org/x/oauth2" - "reflect" - "strconv" - "strings" ) type Server struct { @@ -40,7 +43,7 @@ func (s *Server) init() error { var newImplementer = extension.New(s.registry) var options = []server.Option{ server.WithNewHandler(newImplementer), - server.WithImplementation(schema.Implementation{"Datly", "0.1"}), + server.WithImplementation(schema.Implementation{Name: "Datly", Version: "0.1"}), } issuerURL := s.config.IssuerURL var oauth2Config *oauth2.Config diff --git a/service/executor/expand/data_unit.go b/service/executor/expand/data_unit.go index ad8516e76..784953fc9 100644 --- a/service/executor/expand/data_unit.go +++ b/service/executor/expand/data_unit.go @@ -275,6 +275,17 @@ func (c *DataUnit) Like(columnName string, args interface{}) (string, error) { func (c *DataUnit) NotLike(columnName string, args interface{}) (string, error) { return c.like(columnName, args, false) } +func (c *DataUnit) Expression(expr string, value interface{}) (string, error) { + return c.expression(expr, value) +} + +func (c *DataUnit) expression(expr string, value interface{}) (string, error) { + if value == "" { + return "", nil + } + c.addAll(value) + return expr, nil +} func (c *DataUnit) like(columnName string, args interface{}, inclusive bool) (string, error) { expander, err := bindingsCache.Lookup(args) diff --git a/view/extension/init.go b/view/extension/init.go index db515af42..f05ff7140 100644 --- a/view/extension/init.go +++ b/view/extension/init.go @@ -3,6 +3,8 @@ package extension import ( "encoding/json" "fmt" + "net/http" + dcodec "github.com/viant/datly/view/extension/codec" "github.com/viant/datly/view/extension/handler" "github.com/viant/datly/view/extension/marshaller" @@ -17,14 +19,14 @@ import ( "github.com/viant/xdatly/handler/response/tabular/tjson" "github.com/viant/xdatly/handler/response/tabular/xml" "github.com/viant/xdatly/handler/validator" - "net/http" + + "reflect" + "time" "github.com/viant/xdatly/predicate" "github.com/viant/xdatly/types/core" _ "github.com/viant/xdatly/types/custom" "github.com/viant/xreflect" - "reflect" - "time" ) const ( @@ -119,6 +121,7 @@ func InitRegistry() { PredicateGreaterOrEqual: NewGreaterOrEqualPredicate(), PredicateGreaterThan: NewGreaterThanPredicate(), PredicateLike: NewLikePredicate(), + PredicateExpr: NewExprPredicate(), PredicateNotLike: NewNotLikePredicate(), PredicateHandler: NewPredicateHandler(), PredicateContains: NewContainsPredicate(), diff --git a/view/extension/predicates.go b/view/extension/predicates.go index 04b0ba098..ae0276e95 100644 --- a/view/extension/predicates.go +++ b/view/extension/predicates.go @@ -2,12 +2,13 @@ package extension import ( "fmt" + "sync" + "github.com/viant/datly/utils/types" codec2 "github.com/viant/datly/view/extension/codec" "github.com/viant/xdatly/codec" "github.com/viant/xdatly/predicate" "github.com/viant/xreflect" - "sync" ) const ( @@ -32,6 +33,7 @@ const ( PredicateExists = "exists" PredicateNotExists = "not_exists" + PredicateExpr = "expr" PredicateCriteriaExists = "exists_criteria" PredicateCriteriaNotExists = "not_exists_criteria" PredicateCriteriaIn = "in_criteria" @@ -225,6 +227,10 @@ func NewEqualPredicate() *Predicate { return binaryPredicate(PredicateEqual, "=") } +func NewColumnExpressionPredicate() *Predicate { + return binaryPredicate(PredicateEqual, "=") +} + func NewLessOrEqualPredicate() *Predicate { return binaryPredicate(PredicateLessOrEqual, "<=") } @@ -333,6 +339,10 @@ func NewLikePredicate() *Predicate { return newLikePredicate(PredicateLike, true) } +func NewExprPredicate() *Predicate { + return newExprPredicate(PredicateExpr) +} + func NewNotLikePredicate() *Predicate { return newLikePredicate(PredicateNotLike, false) } @@ -362,6 +372,23 @@ func newLikePredicate(name string, inclusive bool) *Predicate { } } +func newExprPredicate(expr string) *Predicate { + args := []*predicate.NamedArgument{ + { + Name: "Expression", + Position: 0, + }, + } + criteria := fmt.Sprintf(`$criteria.Expression($Expression, $FilterValue)`) + return &Predicate{ + Template: &predicate.Template{ + Name: expr, + Source: " " + criteria, + Args: args, + }, + } +} + func NewContainsPredicate() *Predicate { return newContainsPredicate(PredicateContains, true) } diff --git a/view/tags/codec.go b/view/tags/codec.go index a16be7509..d606ed717 100644 --- a/view/tags/codec.go +++ b/view/tags/codec.go @@ -1,9 +1,9 @@ package tags import ( - "fmt" - "github.com/viant/tagly/tags" "strings" + + "github.com/viant/tagly/tags" ) // CodecTag codec tag @@ -31,10 +31,11 @@ func (t *Tag) updatedCodec(key string, value string) (err error) { } tag.Body = string(data) default: + expr := key if value != "" { - return fmt.Errorf("invalid argument %s", value) + expr += " =" + value } - tag.Arguments = append(tag.Arguments, key) + tag.Arguments = append(tag.Arguments, expr) } return err } diff --git a/view/tags/predicate.go b/view/tags/predicate.go index e66ef5e76..956a2bc5b 100644 --- a/view/tags/predicate.go +++ b/view/tags/predicate.go @@ -2,9 +2,10 @@ package tags import ( "fmt" - "github.com/viant/tagly/tags" "strconv" "strings" + + "github.com/viant/tagly/tags" ) // PredicateTag Predicate tag @@ -70,10 +71,11 @@ func (t *Tag) updatedPredicate(key string, value string) (err error) { return fmt.Errorf("invalid predicate ensure: %s %w", value, err) } default: + expr := key if value != "" { - return fmt.Errorf("invalid argument %s", value) + expr = key + "=" + value } - tag.Arguments = append(tag.Arguments, key) + tag.Arguments = append(tag.Arguments, expr) } return err } From 9b734aaee1343879abd236fa3d038f43f356f478 Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 18 Sep 2025 14:30:31 -0700 Subject: [PATCH 030/117] updated deparemoved goccy josn --- gateway/route.go | 2 +- go.mod | 2 +- go.sum | 3 +-- repository/logging/logging.go | 6 +++--- service/reader/handler/handler.go | 10 +++++++--- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/gateway/route.go b/gateway/route.go index 24e682d3d..4bec8528a 100644 --- a/gateway/route.go +++ b/gateway/route.go @@ -2,7 +2,7 @@ package gateway import ( "context" - "github.com/goccy/go-json" + "encoding/json" "github.com/viant/afs/url" "github.com/viant/datly/gateway/router" "github.com/viant/datly/repository" diff --git a/go.mod b/go.mod index 51eacc09c..6b8b056c3 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/aws/aws-lambda-go v1.31.0 github.com/francoispqt/gojay v1.2.13 github.com/go-sql-driver/mysql v1.7.0 - github.com/goccy/go-json v0.10.5 github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/google/gops v0.3.23 github.com/google/uuid v1.6.0 @@ -106,6 +105,7 @@ require ( github.com/go-errors/errors v1.5.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/go.sum b/go.sum index 9508d64ec..717c1ab96 100644 --- a/go.sum +++ b/go.sum @@ -787,9 +787,8 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= diff --git a/repository/logging/logging.go b/repository/logging/logging.go index c0054ea70..00440ac60 100644 --- a/repository/logging/logging.go +++ b/repository/logging/logging.go @@ -1,8 +1,8 @@ package logging import ( + "encoding/json" "fmt" - "github.com/goccy/go-json" "github.com/viant/xdatly/handler/exec" "strconv" "time" @@ -15,7 +15,7 @@ func Log(config *Config, execContext *exec.Context) { execContext.Metrics = execContext.Metrics.HideMetrics() } if config.IsAuditEnabled() { - data, _ := json.MarshalNoEscape(execContext) + data, _ := json.Marshal(execContext) fmt.Println("[AUDIT] " + string(data)) } if config.IsTracingEnabled() { @@ -42,7 +42,7 @@ func Log(config *Config, execContext *exec.Context) { } else { trace.Spans[0].SetStatusFromHTTPCode(execContext.StatusCode) } - traceData, _ := json.MarshalNoEscape(trace) + traceData, _ := json.Marshal(trace) fmt.Println("[TRACE] " + string(traceData)) } } diff --git a/service/reader/handler/handler.go b/service/reader/handler/handler.go index f85797711..6e83335e3 100644 --- a/service/reader/handler/handler.go +++ b/service/reader/handler/handler.go @@ -2,8 +2,8 @@ package handler import ( "context" + "encoding/json" - goJson "github.com/goccy/go-json" "github.com/viant/datly/gateway/router/status" _ "github.com/viant/datly/repository/locator/async" _ "github.com/viant/datly/repository/locator/component" @@ -139,7 +139,11 @@ func (h *Handler) publishViewSummaryIfNeeded(aView *view.View, ret *Response) { if templateMeta.Kind != view.MetaKindHeader { return } - data, err := goJson.MarshalNoEscape(ret.Reader.DataSummary) + var data []byte + var err error + if ret.Reader.DataSummary != nil { + data, err = json.Marshal(ret.Reader.DataSummary) + } if err != nil { ret.StatusCode = http.StatusInternalServerError ret.Status.Status = "error" @@ -157,7 +161,7 @@ func (h *Handler) publishMetricsIfNeeded(aSession *reader.Session, ret *Response if info.Executions == nil { continue } - data, err := goJson.MarshalNoEscape(info) + data, err := json.Marshal(info) if err != nil { continue } From 198248fc665ad552d4299ec0cdd2d8ee0645e86e Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 23 Sep 2025 11:59:23 -0700 Subject: [PATCH 031/117] added retry on invalid connection --- service/reader/service.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/service/reader/service.go b/service/reader/service.go index 63ca09436..d3701f9bc 100644 --- a/service/reader/service.go +++ b/service/reader/service.go @@ -5,7 +5,9 @@ import ( "database/sql" "fmt" "reflect" + "strings" "sync" + "sync/atomic" "time" "unsafe" @@ -515,12 +517,25 @@ func (s *Service) queryWithHandler(ctx context.Context, session *Session, aView if session.DryRun { return []*response.SQLExecution{stats}, nil } + + retires := uint32(0) +BEGIN: reader, err := read.New(ctx, db, parametrizedSQL.SQL, collector.NewItem(), options...) + + isInvalidConnection := err != nil && strings.Contains(err.Error(), "invalid connection") + if isInvalidConnection && atomic.AddUint32(&retires, 1) < 3 { + db, err = aView.Connector.DB() + if err != nil { + return nil, fmt.Errorf("failed to connect to db: %w", err) + } + goto BEGIN + } if err != nil { stats.SetError(err) anExec, err := s.HandleSQLError(err, session, aView, parametrizedSQL, stats) return []*response.SQLExecution{anExec}, err } + defer func() { stmt := reader.Stmt() if stmt == nil { @@ -529,7 +544,17 @@ func (s *Service) queryWithHandler(ctx context.Context, session *Session, aView _ = stmt.Close() }() err = reader.QueryAll(ctx, handler, parametrizedSQL.Args...) + + isInvalidConnection = err != nil && strings.Contains(err.Error(), "invalid connection") + if isInvalidConnection && atomic.AddUint32(&retires, 1) < 3 { + db, err = aView.Connector.DB() + if err != nil { + return nil, fmt.Errorf("failed to connect to db: %w", err) + } + goto BEGIN + } end := time.Now() + aView.Logger.ReadingData(end.Sub(begin), parametrizedSQL.SQL, *readData, parametrizedSQL.Args, err) if err != nil { stats.SetError(err) From cf7d3954d83a8fdda7fd6057013a35e32af1b3f3 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 23 Sep 2025 13:35:27 -0700 Subject: [PATCH 032/117] added retry on invalid connection --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6b8b056c3..fa54285be 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b github.com/viant/pgo v0.11.0 github.com/viant/scy v0.24.0 - github.com/viant/sqlx v0.17.7 + github.com/viant/sqlx v0.17.8 github.com/viant/structql v0.5.2 github.com/viant/toolbox v0.37.0 github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 diff --git a/go.sum b/go.sum index 717c1ab96..3914ffdf7 100644 --- a/go.sum +++ b/go.sum @@ -1140,6 +1140,8 @@ github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= github.com/viant/sqlx v0.17.7 h1:drUv3N8mOboq917gnmcT9zC4G9vj4jU11bO/SsLpmc8= github.com/viant/sqlx v0.17.7/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= +github.com/viant/sqlx v0.17.8 h1:YxGTrXC2B1JmDz1qp8G+G9hGPk7XCRevWN1E4E+ZlCI= +github.com/viant/sqlx v0.17.8/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= github.com/viant/structology v0.6.1/go.mod h1:63XfkzUyNw7wdi99HJIsH2Rg3d5AOumqbWLUYytOkxU= github.com/viant/structql v0.5.2 h1:0dAratszxC6AD/TNaV8BnLQQprNO5GJHaKjmszrIoeY= From e7d7ab5b2a30b9602f7042d8bc6bb970acffa860 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 24 Sep 2025 07:53:00 -0700 Subject: [PATCH 033/117] enhanced marhsller --- gateway/router/marshal/json/cache.go | 26 ++++++++++++++++--- gateway/router/marshal/json/init.go | 2 ++ .../router/marshal/json/marshaller_custom.go | 2 +- gateway/router/marshal/json/option.go | 4 +-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/gateway/router/marshal/json/cache.go b/gateway/router/marshal/json/cache.go index cd79eba61..b5c562932 100644 --- a/gateway/router/marshal/json/cache.go +++ b/gateway/router/marshal/json/cache.go @@ -121,8 +121,11 @@ func (c *pathCache) getMarshaller(rType reflect.Type, config *config.IOConfig, p } aConfig := c.parseConfig(options) - if (aConfig == nil || !aConfig.ignoreCustomUnmarshaller) && rType.Implements(unmarshallerIntoType) { - return newCustomUnmarshaller(rType, config, path, outputPath, tag, c.parent) + // Keep UnmarshalerInto precedence for non-structs; structs handled below to honor gojay first. + if rType.Kind() != reflect.Struct { + if (aConfig == nil || !aConfig.IgnoreCustomUnmarshaller) && rType.Implements(unmarshallerIntoType) { + return newCustomUnmarshaller(rType, config, path, outputPath, tag, c.parent) + } } switch rType { @@ -212,12 +215,27 @@ func (c *pathCache) getMarshaller(rType reflect.Type, config *config.IOConfig, p return newTimeMarshaller(tag, config), nil } - marshaller, err := newStructMarshaller(config, rType, path, outputPath, tag, c.parent) + // Build base struct marshaller first. + base, err := newStructMarshaller(config, rType, path, outputPath, tag, c.parent) if err != nil { return nil, err } - return marshaller, nil + // If struct defines gojay interfaces, wrap the base. + if aConfig == nil || !aConfig.IgnoreCustomMarshaller { + hasMarshal := rType.Implements(marshalerJSONObjectType) || reflect.PtrTo(rType).Implements(marshalerJSONObjectType) + hasUnmarshal := rType.Implements(unmarshalerJSONObjectType) || reflect.PtrTo(rType).Implements(unmarshalerJSONObjectType) + if hasMarshal || hasUnmarshal { + return newGojayObjectMarshaller(getXType(rType), getXType(reflect.PtrTo(rType)), base, hasMarshal, hasUnmarshal), nil + } + } + + // Otherwise, allow custom unmarshaller on structs if defined. + if (aConfig == nil || !aConfig.IgnoreCustomUnmarshaller) && rType.Implements(unmarshallerIntoType) { + return newCustomUnmarshaller(rType, config, path, outputPath, tag, c.parent) + } + + return base, nil case reflect.Interface: marshaller, err := newInterfaceMarshaller(rType, config, path, outputPath, tag, c.parent) diff --git a/gateway/router/marshal/json/init.go b/gateway/router/marshal/json/init.go index cacb47602..31eebb40e 100644 --- a/gateway/router/marshal/json/init.go +++ b/gateway/router/marshal/json/init.go @@ -13,6 +13,8 @@ import ( var rawMessageType = reflect.TypeOf(json.RawMessage{}) var unmarshallerIntoType = reflect.TypeOf((*UnmarshalerInto)(nil)).Elem() +var marshalerJSONObjectType = reflect.TypeOf((*gojay.MarshalerJSONObject)(nil)).Elem() +var unmarshalerJSONObjectType = reflect.TypeOf((*gojay.UnmarshalerJSONObject)(nil)).Elem() var mapStringIfaceType = reflect.TypeOf(map[string]interface{}{}) var decData *xunsafe.Field var decCur *xunsafe.Field diff --git a/gateway/router/marshal/json/marshaller_custom.go b/gateway/router/marshal/json/marshaller_custom.go index eb73890c3..81ca8fbd8 100644 --- a/gateway/router/marshal/json/marshaller_custom.go +++ b/gateway/router/marshal/json/marshaller_custom.go @@ -21,7 +21,7 @@ type customMarshaller struct { } func newCustomUnmarshaller(rType reflect.Type, config *config.IOConfig, path string, outputPath string, tag *format.Tag, cache *marshallersCache) (marshaler, error) { - marshaller, err := cache.loadMarshaller(rType, config, path, outputPath, tag, &cacheConfig{ignoreCustomUnmarshaller: true}) + marshaller, err := cache.loadMarshaller(rType, config, path, outputPath, tag, &cacheConfig{IgnoreCustomUnmarshaller: true}) if err != nil { return nil, err } diff --git a/gateway/router/marshal/json/option.go b/gateway/router/marshal/json/option.go index cd1855380..82a8e2dd1 100644 --- a/gateway/router/marshal/json/option.go +++ b/gateway/router/marshal/json/option.go @@ -26,6 +26,6 @@ func (o Options) FormatTag() *format.Tag { } type cacheConfig struct { - ignoreCustomUnmarshaller bool - ignoreCustomMarshaller bool + IgnoreCustomUnmarshaller bool + IgnoreCustomMarshaller bool } From 148f00b058c2b1e6619ac7c074198f3ae86d1da5 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 24 Sep 2025 14:36:14 -0700 Subject: [PATCH 034/117] enhanced marhsller --- .../marshal/json/marshaller_gojay_object.go | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 gateway/router/marshal/json/marshaller_gojay_object.go diff --git a/gateway/router/marshal/json/marshaller_gojay_object.go b/gateway/router/marshal/json/marshaller_gojay_object.go new file mode 100644 index 000000000..af3cbbec3 --- /dev/null +++ b/gateway/router/marshal/json/marshaller_gojay_object.go @@ -0,0 +1,68 @@ +package json + +import ( + "github.com/francoispqt/gojay" + "github.com/viant/xunsafe" + "unsafe" +) + +// gojayObjectMarshaller delegates to gojay's Marshaler/UnmarshalerJSONObject when available, +// and falls back to the generic struct marshaller for the other direction. +type gojayObjectMarshaller struct { + valueType *xunsafe.Type + addrType *xunsafe.Type + fallback marshaler + useMarshal bool + useUnmarshal bool +} + +func newGojayObjectMarshaller(valueType *xunsafe.Type, addrType *xunsafe.Type, fallback marshaler, useMarshal, useUnmarshal bool) *gojayObjectMarshaller { + return &gojayObjectMarshaller{ + valueType: valueType, + addrType: addrType, + fallback: fallback, + useMarshal: useMarshal, + useUnmarshal: useUnmarshal, + } +} + +func (g *gojayObjectMarshaller) MarshallObject(ptr unsafe.Pointer, session *MarshallSession) error { + if ptr == nil { + session.Write(nullBytes) + return nil + } + + if g.useMarshal { + // Prefer pointer receiver if (*T) implements MarshalerJSONObject + if m, ok := g.addrType.Value(ptr).(gojay.MarshalerJSONObject); ok { + enc := gojay.NewEncoder(session.Buffer) + return enc.EncodeObject(m) + } + // Fallback to value receiver if (T) implements MarshalerJSONObject + if m, ok := g.valueType.Interface(ptr).(gojay.MarshalerJSONObject); ok { + enc := gojay.NewEncoder(session.Buffer) + return enc.EncodeObject(m) + } + // If neither matched at runtime, fallback to generic marshaller + } + return g.fallback.MarshallObject(ptr, session) +} + +func (g *gojayObjectMarshaller) UnmarshallObject(pointer unsafe.Pointer, decoder *gojay.Decoder, auxiliaryDecoder *gojay.Decoder, session *UnmarshalSession) error { + if !g.useUnmarshal { + return g.fallback.UnmarshallObject(pointer, decoder, auxiliaryDecoder, session) + } + + d := decoder + if auxiliaryDecoder != nil { + d = auxiliaryDecoder + } + + // Prefer pointer receiver only; value receiver cannot mutate destination reliably. + if u, ok := g.addrType.Value(pointer).(gojay.UnmarshalerJSONObject); ok { + return d.Object(u) + } + + // If neither matched at runtime, fallback to generic unmarshaller + return g.fallback.UnmarshallObject(pointer, decoder, auxiliaryDecoder, session) +} From 16e573bd58876da1df099ab70e5eaa3966ebae62 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 24 Sep 2025 14:43:06 -0700 Subject: [PATCH 035/117] enhanced marhsller --- gateway/router/marshal/json/cache.go | 31 +++++++++++++------ .../router/marshal/json/marshaller_struct.go | 4 ++- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/gateway/router/marshal/json/cache.go b/gateway/router/marshal/json/cache.go index b5c562932..4329b4905 100644 --- a/gateway/router/marshal/json/cache.go +++ b/gateway/router/marshal/json/cache.go @@ -3,13 +3,14 @@ package json import ( "bytes" "fmt" + "reflect" + "sync" + "github.com/viant/datly/gateway/router/marshal/config" "github.com/viant/tagly/format" "github.com/viant/tagly/format/text" "github.com/viant/xreflect" "github.com/viant/xunsafe" - "reflect" - "sync" ) var buffersPool *buffers @@ -215,22 +216,32 @@ func (c *pathCache) getMarshaller(rType reflect.Type, config *config.IOConfig, p return newTimeMarshaller(tag, config), nil } - // Build base struct marshaller first. + // Decide if type uses gojay; build base without init to handle self-references safely. + hasMarshal := (aConfig == nil || !aConfig.IgnoreCustomMarshaller) && (rType.Implements(marshalerJSONObjectType) || reflect.PtrTo(rType).Implements(marshalerJSONObjectType)) + hasUnmarshal := (aConfig == nil || !aConfig.IgnoreCustomMarshaller) && (rType.Implements(unmarshalerJSONObjectType) || reflect.PtrTo(rType).Implements(unmarshalerJSONObjectType)) + base, err := newStructMarshaller(config, rType, path, outputPath, tag, c.parent) if err != nil { return nil, err } - // If struct defines gojay interfaces, wrap the base. - if aConfig == nil || !aConfig.IgnoreCustomMarshaller { - hasMarshal := rType.Implements(marshalerJSONObjectType) || reflect.PtrTo(rType).Implements(marshalerJSONObjectType) - hasUnmarshal := rType.Implements(unmarshalerJSONObjectType) || reflect.PtrTo(rType).Implements(unmarshalerJSONObjectType) - if hasMarshal || hasUnmarshal { - return newGojayObjectMarshaller(getXType(rType), getXType(reflect.PtrTo(rType)), base, hasMarshal, hasUnmarshal), nil + if hasMarshal || hasUnmarshal { + // Wrap base with gojay and store wrapper first to break cycles and ensure self-references use wrapper. + wrapper := newGojayObjectMarshaller(getXType(rType), getXType(reflect.PtrTo(rType)), base, hasMarshal, hasUnmarshal) + c.storeMarshaler(rType, wrapper) + if err := base.init(); err != nil { + return nil, err } + return wrapper, nil + } + + // No gojay: store base first to break cycles, then init. + c.storeMarshaler(rType, base) + if err := base.init(); err != nil { + return nil, err } - // Otherwise, allow custom unmarshaller on structs if defined. + // Allow custom unmarshaller on structs if defined and not ignored (only if no gojay used). if (aConfig == nil || !aConfig.IgnoreCustomUnmarshaller) && rType.Implements(unmarshallerIntoType) { return newCustomUnmarshaller(rType, config, path, outputPath, tag, c.parent) } diff --git a/gateway/router/marshal/json/marshaller_struct.go b/gateway/router/marshal/json/marshaller_struct.go index a0d2d1070..bb66bd01d 100644 --- a/gateway/router/marshal/json/marshaller_struct.go +++ b/gateway/router/marshal/json/marshaller_struct.go @@ -68,7 +68,9 @@ func newStructMarshaller(config *config.IOConfig, rType reflect.Type, path strin marshallersIndex: map[string]int{}, } - return result, result.init() + // Initialization is invoked by cache after it stores the marshaller (or wrapper) + // to break cycles for self-referential types. + return result, nil } func (s *structMarshaller) UnmarshallObject(pointer unsafe.Pointer, decoder *gojay.Decoder, auxiliaryDecoder *gojay.Decoder, session *UnmarshalSession) error { From 6208351fc5d4a2673c205c82a00455b81410e0c4 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 24 Sep 2025 14:48:15 -0700 Subject: [PATCH 036/117] enhanced marhsller --- gateway/router/marshal/json/cache.go | 13 +++++--- .../marshal/json/marshaller_deferred.go | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 gateway/router/marshal/json/marshaller_deferred.go diff --git a/gateway/router/marshal/json/cache.go b/gateway/router/marshal/json/cache.go index 4329b4905..728af816d 100644 --- a/gateway/router/marshal/json/cache.go +++ b/gateway/router/marshal/json/cache.go @@ -106,12 +106,17 @@ func (c *pathCache) loadOrGetMarshaller(rType reflect.Type, config *config.IOCon return value.(marshaler), nil } - aMarshaler, err := c.getMarshaller(rType, config, path, outputPath, tag, options...) + // Place a deferred placeholder to break recursive graphs for this path and type. + placeholder := &deferredMarshaller{} + c.storeMarshaler(rType, placeholder) + aMarshaler, err := c.getMarshaller(rType, config, path, outputPath, tag, options...) if err != nil { return nil, err } + // Swap placeholder with the real marshaller and set target for any users that captured it. + placeholder.setTarget(aMarshaler) c.storeMarshaler(rType, aMarshaler) return aMarshaler, nil } @@ -226,17 +231,15 @@ func (c *pathCache) getMarshaller(rType reflect.Type, config *config.IOConfig, p } if hasMarshal || hasUnmarshal { - // Wrap base with gojay and store wrapper first to break cycles and ensure self-references use wrapper. + // Wrap base with gojay; placeholder at loadOrGet level already breaks cycles. wrapper := newGojayObjectMarshaller(getXType(rType), getXType(reflect.PtrTo(rType)), base, hasMarshal, hasUnmarshal) - c.storeMarshaler(rType, wrapper) if err := base.init(); err != nil { return nil, err } return wrapper, nil } - // No gojay: store base first to break cycles, then init. - c.storeMarshaler(rType, base) + // No gojay: just init base and return (placeholder already in place). if err := base.init(); err != nil { return nil, err } diff --git a/gateway/router/marshal/json/marshaller_deferred.go b/gateway/router/marshal/json/marshaller_deferred.go new file mode 100644 index 000000000..fef24a83d --- /dev/null +++ b/gateway/router/marshal/json/marshaller_deferred.go @@ -0,0 +1,31 @@ +package json + +import ( + "fmt" + "github.com/francoispqt/gojay" + "unsafe" +) + +// deferredMarshaller is a placeholder used to break recursive type graphs during construction. +// It forwards calls to the actual target once it is set. +type deferredMarshaller struct { + target marshaler +} + +func (d *deferredMarshaller) setTarget(m marshaler) { + d.target = m +} + +func (d *deferredMarshaller) MarshallObject(ptr unsafe.Pointer, session *MarshallSession) error { + if d.target == nil { + return fmt.Errorf("marshaller not initialized") + } + return d.target.MarshallObject(ptr, session) +} + +func (d *deferredMarshaller) UnmarshallObject(pointer unsafe.Pointer, decoder *gojay.Decoder, auxiliaryDecoder *gojay.Decoder, session *UnmarshalSession) error { + if d.target == nil { + return fmt.Errorf("marshaller not initialized") + } + return d.target.UnmarshallObject(pointer, decoder, auxiliaryDecoder, session) +} From c5404492eaf77bf094bfbcf0824e3bfe5e25b508 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 24 Sep 2025 14:55:33 -0700 Subject: [PATCH 037/117] enhanced marhsller --- gateway/router/marshal/json/marshaller_struct.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gateway/router/marshal/json/marshaller_struct.go b/gateway/router/marshal/json/marshaller_struct.go index bb66bd01d..23e2392a3 100644 --- a/gateway/router/marshal/json/marshaller_struct.go +++ b/gateway/router/marshal/json/marshaller_struct.go @@ -256,8 +256,8 @@ func (s *structMarshaller) createStructMarshallers(fields *groupedFields, path s } elemType := field.Type - switch elemType.Kind() { - case reflect.Ptr, reflect.Slice: + // Unwrap nested pointers/slices to detect self-references like []*T or [][]*T + for elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Slice { elemType = elemType.Elem() } if elemType == fields.owner { From a782238afa5ee83c831029c03ab46bd34c852aae Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 29 Sep 2025 13:45:57 -0700 Subject: [PATCH 038/117] enhanced marhsller --- doc/extension/EXAMPLES.md | 123 +----------------------------------- go.mod | 1 - service/executor/service.go | 32 +++++++++- 3 files changed, 31 insertions(+), 125 deletions(-) diff --git a/doc/extension/EXAMPLES.md b/doc/extension/EXAMPLES.md index 1e6d6614a..6f476a0a7 100644 --- a/doc/extension/EXAMPLES.md +++ b/doc/extension/EXAMPLES.md @@ -2200,128 +2200,7 @@ go 1.21 require ( github.com/aerospike/aerospike-client-go v4.5.2+incompatible - github.com/aws/aws-lambda-go v1.31.0 - github.com/francoispqt/gojay v1.2.13 - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator v9.31.0+incompatible - github.com/go-sql-driver/mysql v1.7.0 - github.com/goccy/go-json v0.9.11 - github.com/golang-jwt/jwt/v4 v4.4.1 - github.com/google/gops v0.3.23 - github.com/google/uuid v1.3.0 - github.com/jessevdk/go-flags v1.5.0 - github.com/leodido/go-urn v1.2.1 // indirect - github.com/lib/pq v1.10.6 - github.com/mattn/go-sqlite3 v1.14.16 - github.com/onsi/gomega v1.20.2 // indirect - github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.8.4 - github.com/viant/afs v1.24.2 - github.com/viant/afsc v1.9.0 - github.com/viant/assertly v0.9.1-0.20220620174148-bab013f93a60 - github.com/viant/bigquery v0.2.1 - github.com/viant/cloudless v1.8.1 - github.com/viant/dsc v0.16.2 // indirect - github.com/viant/dsunit v0.10.8 - github.com/viant/dyndb v0.1.4-0.20221214043424-27654ab6ed9c - github.com/viant/gmetric v0.2.7-0.20220508155136-c2e3c95db446 - github.com/viant/godiff v0.4.1 - github.com/viant/parsly v0.2.0 - github.com/viant/pgo v0.10.3 - github.com/viant/scy v0.6.0 - github.com/viant/sqlx v0.8.0 - github.com/viant/structql v0.2.2 - github.com/viant/toolbox v0.34.6-0.20221112031702-3e7cdde7f888 - github.com/viant/velty v0.2.0 - github.com/viant/xdatly/types/custom v0.0.0-20230309034540-231985618fc7 - github.com/viant/xreflect v0.0.0-20230303201326-f50afb0feb0d - github.com/viant/xunsafe v0.8.4 - golang.org/x/mod v0.9.0 - golang.org/x/oauth2 v0.7.0 - google.golang.org/api v0.114.0 - gopkg.in/go-playground/assert.v1 v1.2.1 // indirect - gopkg.in/yaml.v3 v3.0.1 -) - -require ( - github.com/viant/govalidator v0.2.1 - github.com/viant/sqlparser v0.3.1-0.20230320162628-96274e82953f - golang.org/x/crypto v0.7.0 // indirect -) - -require ( - github.com/aws/aws-sdk-go v1.44.12 - github.com/aws/aws-sdk-go-v2/config v1.18.3 - github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1 - github.com/viant/structology v0.2.0 - github.com/viant/xdatly/extension v0.0.0-20230323215422-3e5c3147f0e6 - github.com/viant/xdatly/handler v0.0.0-20230619231115-e622dd6aff79 - github.com/viant/xdatly/types/core v0.0.0-20230615201419-f5e46b6b011f -) - -require ( - cloud.google.com/go v0.110.0 // indirect - cloud.google.com/go/compute v1.19.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.13.0 // indirect - cloud.google.com/go/secretmanager v1.10.0 // indirect - cloud.google.com/go/storage v1.29.0 // indirect - github.com/aws/aws-sdk-go-v2 v1.18.0 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect - github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 // indirect - github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8 // indirect - github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sns v1.20.11 // indirect - github.com/aws/aws-sdk-go-v2/service/sqs v1.22.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 // indirect - github.com/aws/smithy-go v1.13.5 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d // indirect - github.com/go-errors/errors v1.4.2 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.8.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/kr/pretty v0.3.0 // indirect - github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect - github.com/lestrrat-go/blackmagic v1.0.0 // indirect - github.com/lestrrat-go/httpcc v1.0.1 // indirect - github.com/lestrrat-go/iter v1.0.1 // indirect - github.com/lestrrat-go/jwx v1.2.25 // indirect - github.com/lestrrat-go/option v1.0.0 // indirect - github.com/michael/mymodule2 v0.0.0-00010101000000-000000000000 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect - github.com/viant/igo v0.1.0 // indirect - github.com/yuin/gopher-lua v0.0.0-20221210110428-332342483e3f // indirect - go.opencensus.io v0.24.0 // indirect - golang.org/x/net v0.9.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/term v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.54.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + .... gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.mod b/go.mod index fa54285be..16e40247d 100644 --- a/go.mod +++ b/go.mod @@ -105,7 +105,6 @@ require ( github.com/go-errors/errors v1.5.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/goccy/go-json v0.10.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/service/executor/service.go b/service/executor/service.go index c89e8fc41..01df6c631 100644 --- a/service/executor/service.go +++ b/service/executor/service.go @@ -4,6 +4,11 @@ import ( "context" "database/sql" "fmt" + "reflect" + "strings" + "sync/atomic" + "time" + "github.com/viant/datly/logger" expand2 "github.com/viant/datly/service/executor/expand" vsession "github.com/viant/datly/service/session" @@ -13,8 +18,6 @@ import ( "github.com/viant/sqlx/option" "github.com/viant/xdatly/handler/exec" "github.com/viant/xdatly/handler/response" - "reflect" - "time" ) type ( @@ -31,6 +34,8 @@ type ( dbSource DBSource collections map[string]*batcher.Collection logger *logger.Adapter + inserted int32 + updated int32 } DBOption func(options *DBOptions) @@ -190,6 +195,9 @@ func (e *Executor) handleUpdate(ctx context.Context, sess *dbSession, db *sql.DB options = append(options, db) updated, err := service.Exec(ctx, executable.Data, options...) + if err == nil { + atomic.AddInt32(&sess.updated, int32(updated)) + } e.logMetrics(ctx, executable.Table, "UPDATE", updated, now, err) return err } @@ -233,6 +241,9 @@ func (e *Executor) handleInsert(ctx context.Context, sess *dbSession, executable } options = append(options, tx) inserted, _, err = service.Exec(ctx, executable.Data, options...) + if err == nil { + atomic.AddInt32(&sess.inserted, int32(inserted)) + } e.logMetrics(ctx, executable.Table, "INSERT", inserted, started, err) return err } @@ -252,6 +263,23 @@ func (e *Executor) handleInsert(ctx context.Context, sess *dbSession, executable options = append(options, option.BatchSize(batchSize)) options = append(options, e.dbOptions(db, sess)) inserted, _, err = service.Exec(ctx, executable.Data, options...) + if err == nil { + atomic.AddInt32(&sess.inserted, int32(inserted)) + } + isInvalidConnection := err != nil && strings.Contains(err.Error(), "invalid connection") + if isInvalidConnection && atomic.LoadInt32(&sess.inserted) == 0 && atomic.LoadInt32(&sess.updated) == 0 { + var dErr error + db, dErr = sess.dbSource.Db(ctx) + if dErr != nil { + return fmt.Errorf("failed after retry: %w", err) + } + sess.tx.db = db + sess.tx.tx = nil + if _, err = sess.tx.Tx(); err != nil { + return err + } + inserted, _, err = service.Exec(ctx, executable.Data, options...) + } e.logMetrics(ctx, executable.Table, "INSERT", inserted, started, err) return err } From f8fcc28d4e9927dfb319c32dffd80294f86ac99b Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 7 Oct 2025 06:24:55 -0700 Subject: [PATCH 039/117] expose marshallers, move queryselector to xdatly --- cmd/datly/build.yaml | 2 +- e2e/local/build.yaml | 2 +- e2e/local/regression/regression.yaml | 2 +- gateway/router/handler.go | 21 ++-- gateway/runtime/apigw/deploy.yaml | 2 +- gateway/runtime/gcr/deploy.yaml | 2 +- gateway/runtime/lambda/deploy.yaml | 2 +- go.mod | 10 +- go.sum | 18 ++-- internal/translator/rule.go | 7 +- internal/translator/service.go | 14 ++- repository/component.go | 144 +++++++++++++++++++++++--- repository/contract/meta.go | 5 +- service.go | 36 +++++-- service/executor/extension/session.go | 8 +- service/session/selector.go | 14 ++- view/state.go | 76 ++++---------- view/state/kind/locator/options.go | 19 ++-- 18 files changed, 256 insertions(+), 128 deletions(-) diff --git a/cmd/datly/build.yaml b/cmd/datly/build.yaml index 9b2fefa03..92ae41d35 100644 --- a/cmd/datly/build.yaml +++ b/cmd/datly/build.yaml @@ -9,7 +9,7 @@ pipeline: set_sdk: action: sdk.set target: $target - sdk: go:1.23 + sdk: go:1.25.1 build: action: exec:run target: $target diff --git a/e2e/local/build.yaml b/e2e/local/build.yaml index b9b3f87b3..78fd0be42 100644 --- a/e2e/local/build.yaml +++ b/e2e/local/build.yaml @@ -14,7 +14,7 @@ pipeline: set_sdk: action: sdk.set target: $target - sdk: go:1.23 + sdk: go:1.25.1 buildValidator: action: exec:run diff --git a/e2e/local/regression/regression.yaml b/e2e/local/regression/regression.yaml index f4ce9a18c..10cbbf501 100644 --- a/e2e/local/regression/regression.yaml +++ b/e2e/local/regression/regression.yaml @@ -5,7 +5,7 @@ pipeline: set_sdk: action: sdk.set target: $target - sdk: go:1.23 + sdk: go:1.25.1 database: action: run diff --git a/gateway/router/handler.go b/gateway/router/handler.go index ce7398a41..ef3b129c3 100644 --- a/gateway/router/handler.go +++ b/gateway/router/handler.go @@ -261,11 +261,8 @@ func (r *Handler) writeErrorResponse(ctx context.Context, w http.ResponseWriter, http.Error(w, err.Error(), http.StatusInternalServerError) return } - if aComponent.Content.Marshaller.JSON.CanMarshal() { - data, err = aComponent.Marshaller.JSON.Codec.Marshal(aResponse.State()) - } else { - data, err = aComponent.Marshaller.JSON.JsonMarshaller.Marshal(aResponse.State()) - } + mf := aComponent.MarshalFunc() + data, err = mf(aResponse.State()) if err != nil { w.Write(data) if execCtx != nil { @@ -462,8 +459,10 @@ func (r *Handler) handleComponent(ctx context.Context, request *http.Request, aC options.Append(response.WithHeader("Content-Disposition", fmt.Sprintf(`attachment; filename="%s.xlsx"`, aComponent.Output.GetTitle()))) } } + // Use component-level marshaller with request-scoped options filters := aComponent.Exclusion(aSession.State()) - data, err := aComponent.Content.Marshal(format, aComponent.Output.Field(), output, filters) + mf := aComponent.MarshalFunc(repository.WithRequest(request), repository.WithFormat(format), repository.WithFilters(filters)) + data, err := mf(output) if err != nil { return nil, response.NewError(500, fmt.Sprintf("failed to marshal response: %v", err), response.WithError(err)) } @@ -501,13 +500,9 @@ func (r *Handler) marshalComponentOutput(output interface{}, aComponent *reposit case []byte: return response.NewBuffered(response.WithBytes(actual)), nil default: - var data []byte - var err error - if aComponent.Content.Marshaller.JSON.CanMarshal() { - data, err = aComponent.Content.Marshaller.JSON.Codec.Marshal(output) - } else { - data, err = aComponent.Content.Marshaller.JSON.JsonMarshaller.Marshal(output) - } + // Default to JSON marshalling using component-level marshaller + mf := aComponent.MarshalFunc() + data, err := mf(output) if err != nil { return nil, response.NewError(http.StatusInternalServerError, err.Error(), response.WithError(err)) } diff --git a/gateway/runtime/apigw/deploy.yaml b/gateway/runtime/apigw/deploy.yaml index 5a7d85dc6..0511616b0 100644 --- a/gateway/runtime/apigw/deploy.yaml +++ b/gateway/runtime/apigw/deploy.yaml @@ -25,7 +25,7 @@ pipeline: set_sdk: action: sdk.set target: $target - sdk: go:1.21 + sdk: go:1.25.1 build: package: diff --git a/gateway/runtime/gcr/deploy.yaml b/gateway/runtime/gcr/deploy.yaml index 0257ecf68..7cc921e0d 100644 --- a/gateway/runtime/gcr/deploy.yaml +++ b/gateway/runtime/gcr/deploy.yaml @@ -18,7 +18,7 @@ pipeline: setSdk: action: sdk.set target: $target - sdk: go:1.21 + sdk: go:1.25.1 deploy: buildBinary: diff --git a/gateway/runtime/lambda/deploy.yaml b/gateway/runtime/lambda/deploy.yaml index 6a7fbae63..0ea83df8d 100644 --- a/gateway/runtime/lambda/deploy.yaml +++ b/gateway/runtime/lambda/deploy.yaml @@ -27,7 +27,7 @@ pipeline: set_sdk: action: sdk.set target: $target - sdk: go:1.21 + sdk: go:1.25.1 build: package: diff --git a/go.mod b/go.mod index 16e40247d..4aa5d5121 100644 --- a/go.mod +++ b/go.mod @@ -48,14 +48,14 @@ require ( require ( github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d github.com/viant/firebase v0.1.1 - github.com/viant/jsonrpc v0.7.5 - github.com/viant/mcp v0.5.2 + github.com/viant/jsonrpc v0.9.0 + github.com/viant/mcp v0.6.0 github.com/viant/mcp-protocol v0.5.7 github.com/viant/structology v0.6.1 github.com/viant/tagly v0.2.2 - github.com/viant/xdatly v0.5.4-0.20250806192028-819cadf93282 + github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 - github.com/viant/xdatly/handler v0.0.0-20250806192028-819cadf93282 + github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a github.com/viant/xlsy v0.3.1 @@ -105,6 +105,7 @@ require ( github.com/go-errors/errors v1.5.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -127,6 +128,7 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect + github.com/viant/gosh v0.2.1 // indirect github.com/viant/igo v0.2.0 // indirect github.com/viant/x v0.3.0 // indirect github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca // indirect diff --git a/go.sum b/go.sum index 3914ffdf7..3912edbdf 100644 --- a/go.sum +++ b/go.sum @@ -1124,10 +1124,10 @@ github.com/viant/govalidator v0.3.1 h1:V7f/KgfzbP8fVDc+Kj+jyPvfXxMr2N1x7srOlDV6l github.com/viant/govalidator v0.3.1/go.mod h1:D35Dwx0R8rR1knRxhlseoYvOkiqo24kpMg1/o977i9Y= github.com/viant/igo v0.2.0 h1:ygWmTCinnGPaeV7omJLiyneOpzYZ5kiw7oYz7mUJZVQ= github.com/viant/igo v0.2.0/go.mod h1:7V6AWsLhKWeGzXNTNH3AZiIEKa0m33DrQbdWtapsI74= -github.com/viant/jsonrpc v0.7.5 h1:QiLEVl5nP7j5i55jDQp4HUURKJLf+ENPafTlJT13u38= -github.com/viant/jsonrpc v0.7.5/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= -github.com/viant/mcp v0.5.2 h1:m0Z7LdYOQOs7MhYg7Ql9nZlJDiedHfC86VNRzfKg3Gs= -github.com/viant/mcp v0.5.2/go.mod h1:ybylH9mD3/aVLrT8KQsakmsKxtfw7Kpo4A9hmTuetGw= +github.com/viant/jsonrpc v0.9.0 h1:vTZsApJxTd3Y50ygOBs8HKCJ24NrwgCa7lqG1oYXpdE= +github.com/viant/jsonrpc v0.9.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= +github.com/viant/mcp v0.6.0 h1:+BCsLSW5pux07avEhS550hZno8Y5ZKKSfdLm6NHRU+8= +github.com/viant/mcp v0.6.0/go.mod h1:fb5wpE9kc/R32pNE4Pdo1DR4ZW6+0em3rsFuBHoqmp4= github.com/viant/mcp-protocol v0.5.7 h1:3ifypMAy+oUjQEAsq+XwrAhE/B/3eIes4yXdhoRF9Eo= github.com/viant/mcp-protocol v0.5.7/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28= @@ -1138,8 +1138,6 @@ github.com/viant/scy v0.24.0 h1:KAC3IUARkQxTNSuwBK2YhVBJMOOLN30YaLKHbbuSkMU= github.com/viant/scy v0.24.0/go.mod h1:7uNRS67X45YN+JqTLCcMEhehffVjqrejULEDln9p0Ao= github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns= github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= -github.com/viant/sqlx v0.17.7 h1:drUv3N8mOboq917gnmcT9zC4G9vj4jU11bO/SsLpmc8= -github.com/viant/sqlx v0.17.7/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/sqlx v0.17.8 h1:YxGTrXC2B1JmDz1qp8G+G9hGPk7XCRevWN1E4E+ZlCI= github.com/viant/sqlx v0.17.8/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= @@ -1156,12 +1154,12 @@ github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 h1:zKk+6hqUipkJXCPCH github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85/go.mod h1:Q/UXviI2Nli8WROEpYd/BELMCSvnulQeyNrbPmMiS/Y= github.com/viant/x v0.3.0 h1:/3A0z/uySGxMo6ixH90VAcdjI00w5e3REC1zg5hzhJA= github.com/viant/x v0.3.0/go.mod h1:54jP3qV+nnQdNDaWxEwGTAAzCu9sx9er9htiwTW/Mcw= -github.com/viant/xdatly v0.5.4-0.20250806192028-819cadf93282 h1:CqRQGsior7arN1lQA11oCoWdC/LZv1ObhCOGpdwvR3k= -github.com/viant/xdatly v0.5.4-0.20250806192028-819cadf93282/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= +github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa h1:o5o1CmraGb/LSpfrgmDoMdi9JJGjiopH8cmX98ukJS0= +github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 h1:9Yry3PUBDzc4rWacOYvAq/TKrTV0agvMF0gwm2gaoHI= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259/go.mod h1:fb8YgbVadk8X5ZLz49LWGzWmQlZd7Y/I5wE0ru44bIo= -github.com/viant/xdatly/handler v0.0.0-20250806192028-819cadf93282 h1:oNhkNyC6bRBifxWLyd7MTEFmCMwfg1LaAjKAmubrWCM= -github.com/viant/xdatly/handler v0.0.0-20250806192028-819cadf93282/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= +github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa h1:UzX1wB23RMENSKF5X0fQZR/cIy7wB7z2ODWCIm358IQ= +github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 h1:G+e1MMDxQXUPPlAXVNlRqSLTLra7udGQZUu3hnr0Y8M= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52/go.mod h1:LJN2m8xJjtYNCvyvNrVanJwvzj8+hYCuPswL8H4qRG0= github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a h1:jecH7mH63gj1zJwD18SdvSHM9Ttr9FEOnhHkYfkCNkI= diff --git a/internal/translator/rule.go b/internal/translator/rule.go index 98ba973a2..ec42c5388 100644 --- a/internal/translator/rule.go +++ b/internal/translator/rule.go @@ -67,6 +67,7 @@ type ( IsGeneratation bool XMLUnmarshalType string `json:",omitempty"` JSONUnmarshalType string `json:",omitempty"` + JSONMarshalType string `json:",omitempty"` OutputParameter *inference.Parameter } @@ -132,6 +133,7 @@ func (r *Rule) DSQLSetting() interface{} { DocURLs []string `json:",omitempty"` Internal bool `json:",omitempty"` JSONUnmarshalType string `json:",omitempty"` + JSONMarshalType string `json:",omitempty"` Connector string `json:",omitempty"` contract.ModelContextProtocol contract.Meta @@ -148,6 +150,7 @@ func (r *Rule) DSQLSetting() interface{} { DocURLs: r.DocURLs, Internal: r.Internal, JSONUnmarshalType: r.JSONUnmarshalType, + JSONMarshalType: r.JSONMarshalType, Connector: r.Connector, ModelContextProtocol: r.ModelContextProtocol, Meta: r.Meta, @@ -321,7 +324,9 @@ func (r *Rule) applyDefaults() { if r.XMLUnmarshalType != "" { r.Route.Content.Marshaller.XML.TypeName = r.XMLUnmarshalType } - if r.JSONUnmarshalType != "" { + if r.JSONMarshalType != "" { + r.Route.Content.Marshaller.JSON.TypeName = r.JSONMarshalType + } else if r.JSONUnmarshalType != "" { r.Route.Content.Marshaller.JSON.TypeName = r.JSONUnmarshalType } } diff --git a/internal/translator/service.go b/internal/translator/service.go index 70e71d683..6f7cbcbc2 100644 --- a/internal/translator/service.go +++ b/internal/translator/service.go @@ -329,6 +329,15 @@ func (s *Service) persistRouterRule(ctx context.Context, resource *Resource, ser } route.Component.Meta = resource.Rule.Meta + if route.Component.Meta.DescriptionURI != "" { + URL := url.Join(baseRuleURL, route.Component.Meta.DescriptionURI) + description, err := s.fs.DownloadWithURL(ctx, URL) + if err != nil { + return fmt.Errorf("failed to download meta description: %v %w", URL, err) + } + route.Component.Meta.Description = string(description) + } + route.ModelContextProtocol = resource.Rule.ModelContextProtocol if route.Handler != nil { if route.Component.Output.Type.Schema == nil { @@ -362,7 +371,10 @@ func (s *Service) persistRouterRule(ctx context.Context, resource *Resource, ser if resource.Rule.XMLUnmarshalType != "" { route.Content.Marshaller.XML.TypeName = resource.Rule.XMLUnmarshalType } - if resource.Rule.JSONUnmarshalType != "" { + // JSON marshaller/unmarshaller customization: prefer MarshalType if provided, fallback to UnmarshalType. + if resource.Rule.JSONMarshalType != "" { + route.Content.Marshaller.JSON.TypeName = resource.Rule.JSONMarshalType + } else if resource.Rule.JSONUnmarshalType != "" { route.Content.Marshaller.JSON.TypeName = resource.Rule.JSONUnmarshalType } route.Component.Output.DataFormat = resource.Rule.DataFormat diff --git a/repository/component.go b/repository/component.go index 109ded23a..5a22bdee6 100644 --- a/repository/component.go +++ b/repository/component.go @@ -15,7 +15,7 @@ import ( "github.com/viant/datly/gateway/router/marshal/json" "github.com/viant/datly/internal/setter" "github.com/viant/datly/repository/async" - "github.com/viant/datly/repository/content" + content "github.com/viant/datly/repository/content" "github.com/viant/datly/repository/contract" "github.com/viant/datly/repository/handler" "github.com/viant/datly/repository/version" @@ -261,27 +261,143 @@ func (c *Component) IOConfig() *config.IOConfig { } func (c *Component) UnmarshalFunc(request *http.Request) shared.Unmarshal { - contentType := request.Header.Get(content.HeaderContentType) - setter.SetStringIfEmpty(&contentType, request.Header.Get(strings.ToLower(content.HeaderContentType))) + // Delegate to options-based variant for symmetry and centralization. + return c.UnmarshalFor(WithUnmarshalRequest(request)) +} + +// UnmarshalOption configures unmarshal behavior for Component.UnmarshalFor. +type UnmarshalOption func(*unmarshalOptions) + +type unmarshalOptions struct { + request *http.Request + contentType string + interceptors json.UnmarshalerInterceptors +} + +// WithUnmarshalRequest supplies an http request for content-type detection and transforms. +func WithUnmarshalRequest(r *http.Request) UnmarshalOption { + return func(o *unmarshalOptions) { o.request = r } +} + +// WithContentType overrides the detected content type. +func WithContentType(ct string) UnmarshalOption { + return func(o *unmarshalOptions) { o.contentType = ct } +} + +// WithUnmarshalInterceptors adds/overrides JSON path interceptors. +func WithUnmarshalInterceptors(m json.UnmarshalerInterceptors) UnmarshalOption { + return func(o *unmarshalOptions) { + if o.interceptors == nil { + o.interceptors = json.UnmarshalerInterceptors{} + } + for k, v := range m { + o.interceptors[k] = v + } + } +} + +// UnmarshalFor returns a request-scoped unmarshal function applying content-type detection and transforms. +func (c *Component) UnmarshalFor(opts ...UnmarshalOption) shared.Unmarshal { + options := &unmarshalOptions{} + for _, opt := range opts { + if opt != nil { + opt(options) + } + } + + // Resolve content type if request present + contentType := options.contentType + if contentType == "" && options.request != nil { + contentType = options.request.Header.Get(content.HeaderContentType) + setter.SetStringIfEmpty(&contentType, options.request.Header.Get(strings.ToLower(content.HeaderContentType))) + } + switch contentType { case content.XMLContentType: return c.Content.Marshaller.XML.Unmarshal case content.CSVContentType: return c.Content.CSV.Unmarshal - default: - switch c.Output.DataFormat { - case content.XMLFormat: - return c.Content.Marshaller.XML.Unmarshal + } + // Fallback to data format preference when no content type or not matched + if c.Output.DataFormat == content.XMLFormat { + return c.Content.Marshaller.XML.Unmarshal + } + + // Build JSON path interceptors from component transforms and any user-provided ones + interceptors := options.interceptors + if interceptors == nil { + interceptors = json.UnmarshalerInterceptors{} + } + if options.request != nil { + for _, transform := range c.UnmarshallerInterceptors() { + interceptors[transform.Path] = c.transformFn(options.request, transform) } } - jsonPathInterceptor := json.UnmarshalerInterceptors{} - unmarshallerInterceptors := c.UnmarshallerInterceptors() - for i := range unmarshallerInterceptors { - transform := unmarshallerInterceptors[i] - jsonPathInterceptor[transform.Path] = c.transformFn(request, transform) + + req := options.request // capture for closure + return func(data []byte, dest interface{}) error { + if len(interceptors) > 0 || req != nil { + return c.Content.Marshaller.JSON.JsonMarshaller.Unmarshal(data, dest, interceptors, req) + } + return c.Content.Marshaller.JSON.JsonMarshaller.Unmarshal(data, dest) } - return func(bytes []byte, i interface{}) error { - return c.Content.Marshaller.JSON.JsonMarshaller.Unmarshal(bytes, i, jsonPathInterceptor, request) +} + +// MarshalOption configures marshal behavior for Component.MarshalFunc. +type MarshalOption func(*marshalOptions) + +type marshalOptions struct { + request *http.Request + format string + field string + filters []*json.FilterEntry +} + +// WithRequest supplies an http request for deriving format and state-based exclusions. +func WithRequest(r *http.Request) MarshalOption { return func(o *marshalOptions) { o.request = r } } + +// WithFormat overrides the output format (e.g. content.JSONFormat, content.CSVFormat, etc.). +func WithFormat(format string) MarshalOption { return func(o *marshalOptions) { o.format = format } } + +// WithField overrides the field used by tabular JSON embedding. +func WithField(field string) MarshalOption { return func(o *marshalOptions) { o.field = field } } + +// WithFilters sets explicit JSON field filters (exclusion-based projection). +func WithFilters(filters []*json.FilterEntry) MarshalOption { + return func(o *marshalOptions) { o.filters = filters } +} + +// MarshalFunc returns a request-scoped marshaller closure applying options like format and exclusions. +// If no format is specified, it defaults to JSON for non-reader services and derives from request for readers. +func (c *Component) MarshalFunc(opts ...MarshalOption) shared.Marshal { + options := &marshalOptions{} + for _, opt := range opts { + if opt != nil { + opt(options) + } + } + + // Resolve format + format := options.format + if format == "" { + if options.request != nil && c.Service == service.TypeReader { + format = c.Output.Format(options.request.URL.Query()) + } else { + format = content.JSONFormat + } + } + + // Resolve field (used for tabular JSON embedding) + field := options.field + if field == "" { + field = c.Output.Field() + } + + // Resolve filters (explicit only) + filters := options.filters + + return func(src interface{}) ([]byte, error) { + return c.Content.Marshal(format, field, src, filters) } } diff --git a/repository/contract/meta.go b/repository/contract/meta.go index 878128b5e..8b0cfa71a 100644 --- a/repository/contract/meta.go +++ b/repository/contract/meta.go @@ -7,8 +7,9 @@ import ( // MCP Model Configuration Protocol path integration type Meta struct { - Name string `json:",omitempty" yaml:"Name"` // name of the MCP - Description string `json:",omitempty" yaml:"Description"` // optional description for documentation purposes + Name string `json:",omitempty" yaml:"Name"` // name of the MCP + Description string `json:",omitempty" yaml:"Description"` // optional description for documentation purposes + DescriptionURI string `json:",omitempty" yaml:"DescriptionURI"` } type ModelContextProtocol struct { diff --git a/service.go b/service.go index 68f537d55..78d5acf85 100644 --- a/service.go +++ b/service.go @@ -4,6 +4,7 @@ import ( "context" _ "embed" "fmt" + "github.com/viant/cloudless/async/mbus" "github.com/viant/datly/gateway" "github.com/viant/datly/repository" @@ -17,20 +18,22 @@ import ( "github.com/viant/datly/service/session" "github.com/viant/datly/view" "github.com/viant/datly/view/extension" + "github.com/viant/datly/view/state/kind/locator" verifier2 "github.com/viant/scy/auth/jwt/verifier" hstate "github.com/viant/xdatly/handler/state" + "net/http" + nurl "net/url" + "reflect" + "strings" + "time" + "github.com/viant/datly/view/state" "github.com/viant/scy/auth/jwt" "github.com/viant/scy/auth/jwt/signer" "github.com/viant/structology" "github.com/viant/xdatly/codec" xhandler "github.com/viant/xdatly/handler" - "net/http" - nurl "net/url" - "reflect" - "strings" - "time" ) //go:embed Version @@ -50,16 +53,18 @@ type ( } sessionOptions struct { - request *http.Request - resource state.Resource - form *hstate.Form + request *http.Request + resource state.Resource + form *hstate.Form + querySelectors []*hstate.NamedQuerySelector } SessionOption func(o *sessionOptions) operateOptions struct { - path *contract.Path - component *repository.Component - session *session.Session + path *contract.Path + component *repository.Component + session *session.Session + output interface{} input interface{} sessionOptions []SessionOption @@ -151,6 +156,12 @@ func WithForm(form *hstate.Form) SessionOption { } } +func WithQuerySelectors(selectors ...*hstate.NamedQuerySelector) SessionOption { + return func(o *sessionOptions) { + o.querySelectors = selectors + } +} + func WithStateResource(resource state.Resource) SessionOption { return func(o *sessionOptions) { o.resource = resource @@ -160,6 +171,9 @@ func WithStateResource(resource state.Resource) SessionOption { func (s *Service) NewComponentSession(aComponent *repository.Component, opts ...SessionOption) *session.Session { sessionOpt := newSessionOptions(opts) options := aComponent.LocatorOptions(sessionOpt.request, sessionOpt.form, aComponent.UnmarshalFunc(sessionOpt.request)) + if sessionOpt.querySelectors != nil { + options = append(options, locator.WithQuerySelectors(sessionOpt.querySelectors)) + } aSession := session.New(aComponent.View, session.WithLocatorOptions(options...), session.WithAuth(s.repository.Auth()), session.WithStateResource(sessionOpt.resource), session.WithOperate(s.operator.Operate)) diff --git a/service/executor/extension/session.go b/service/executor/extension/session.go index d52f72f5d..9fbfe51fc 100644 --- a/service/executor/extension/session.go +++ b/service/executor/extension/session.go @@ -19,7 +19,7 @@ import ( type ( Session struct { sqlService SqlServiceFn - stater state.Stater + injector state.Injector validator *validator.Service differ *differ.Service mbus *xmbus.Service @@ -92,7 +92,7 @@ func (s *Session) Db(opts ...sqlx.Option) (*sqlx.Service, error) { } func (s *Session) Stater() *state.Service { - return state.New(s.stater) + return state.New(s.injector) } func (s *Session) FlushTemplate(ctx context.Context) error { @@ -148,8 +148,8 @@ func WithMessageBus(messageBusses []*mbus.Resource) Option { } } -func WithStater(stater state.Stater) Option { +func WithStater(injector state.Injector) Option { return func(s *Session) { - s.stater = stater + s.injector = injector } } diff --git a/service/session/selector.go b/service/session/selector.go index 895a953d2..e4a39b8d3 100644 --- a/service/session/selector.go +++ b/service/session/selector.go @@ -3,13 +3,14 @@ package session import ( "context" "fmt" + "strconv" + "strings" + "github.com/viant/datly/service/session/criteria" "github.com/viant/datly/view" "github.com/viant/tagly/format/text" "github.com/viant/xdatly/codec" "github.com/viant/xdatly/handler/response" - "strconv" - "strings" ) func (s *Session) setQuerySelector(ctx context.Context, ns *view.NamespaceView, opts *Options) (err error) { @@ -18,6 +19,14 @@ func (s *Session) setQuerySelector(ctx context.Context, ns *view.NamespaceView, return nil } + selector := s.state.Lookup(ns.View) + + if opts != nil && opts.locatorOpt != nil && opts.locatorOpt.QuerySelectors != nil { //override selector + querySelectors := opts.locatorOpt.QuerySelectors + if namedSelector := querySelectors.Find(ns.View.Name); namedSelector != nil { + selector.QuerySelector = namedSelector.QuerySelector + } + } if err = s.populateFieldQuerySelector(ctx, ns, opts); err != nil { return response.NewParameterError(ns.View.Name, selectorParameters.FieldsParameter.Name, err) } @@ -36,7 +45,6 @@ func (s *Session) setQuerySelector(ctx context.Context, ns *view.NamespaceView, if err = s.populatePageQuerySelector(ctx, ns, opts); err != nil { return response.NewParameterError(ns.View.Name, selectorParameters.PageParameter.Name, err) } - selector := s.state.Lookup(ns.View) if selector.Limit == 0 && selector.Offset != 0 { return fmt.Errorf("can't use offset without limit - view: %v", ns.View.Name) } diff --git a/view/state.go b/view/state.go index a7ff10ece..8bfd3715b 100644 --- a/view/state.go +++ b/view/state.go @@ -1,12 +1,14 @@ package view import ( + "strings" + "sync" + "github.com/viant/datly/view/state/predicate" "github.com/viant/sqlx/io/read/cache" "github.com/viant/structology" "github.com/viant/tagly/format/text" - "strings" - "sync" + "github.com/viant/xdatly/handler/state" ) // Statelet allows customizing View fetched from Database @@ -14,9 +16,18 @@ type ( //InputType represents view state Statelet struct { - Template *structology.State - QuerySelector + //SELECTORS + DatabaseFormat text.CaseFormat + OutputFormat text.CaseFormat + Template *structology.State + state.QuerySelector QuerySettings + filtersMu sync.Mutex + initialized bool + _columnNames map[string]bool + result *cache.ParmetrizedQuery + predicate.Filters + Ignore bool } QuerySettings struct { @@ -24,42 +35,8 @@ type ( SyncFlag bool ContentFormat string } - - QuerySelector struct { - //SELECTORS - DatabaseFormat text.CaseFormat - OutputFormat text.CaseFormat - Columns []string `json:",omitempty"` - Fields []string `json:",omitempty"` - OrderBy string `json:",omitempty"` - Offset int `json:",omitempty"` - Limit int `json:",omitempty"` - - Criteria string `json:",omitempty"` - Placeholders []interface{} `json:",omitempty"` - Page int - Ignore bool - predicate.Filters - - initialized bool - _columnNames map[string]bool - result *cache.ParmetrizedQuery - filtersMu sync.Mutex - } ) -func (s *QuerySelector) CurrentLimit() int { - return s.Limit -} - -func (s *QuerySelector) CurrentOffset() int { - return s.Offset -} - -func (s *QuerySelector) CurrentPage() int { - return s.Page -} - // Init initializes Statelet func (s *Statelet) Init(aView *View) { if aView != nil && s.Template == nil && aView.Template.stateType != nil { @@ -72,12 +49,12 @@ func (s *Statelet) Init(aView *View) { } // Has checks if Field is present in Template.Columns -func (s *QuerySelector) Has(field string) bool { +func (s *Statelet) Has(field string) bool { _, ok := s._columnNames[field] return ok } -func (s *QuerySelector) Add(fieldName string, isHolder bool) { +func (s *Statelet) Add(fieldName string, isHolder bool) { toLower := strings.ToLower(fieldName) if _, ok := s._columnNames[toLower]; ok { return @@ -95,28 +72,21 @@ func (s *QuerySelector) Add(fieldName string, isHolder bool) { } } -func (s *QuerySelector) SetCriteria(expanded string, placeholders []interface{}) { - s.Criteria = expanded - s.Placeholders = placeholders -} - // AppendFilters safely appends filters to the selector's Filters to avoid data races. func (s *Statelet) AppendFilters(filters predicate.Filters) { if len(filters) == 0 { return } - s.QuerySelector.filtersMu.Lock() - s.QuerySelector.Filters = append(s.QuerySelector.Filters, filters...) - s.QuerySelector.filtersMu.Unlock() + s.filtersMu.Lock() + s.Filters = append(s.Filters, filters...) + s.filtersMu.Unlock() } // NewStatelet creates a selector func NewStatelet() *Statelet { return &Statelet{ - QuerySelector: QuerySelector{ - _columnNames: map[string]bool{}, - initialized: true, - }, + _columnNames: map[string]bool{}, + initialized: true, } } @@ -127,7 +97,7 @@ type State struct { } // QuerySelector returns query selector -func (s *State) QuerySelector(view *View) *QuerySelector { +func (s *State) QuerySelector(view *View) *state.QuerySelector { statelet := s.Lookup(view) if statelet == nil { return nil diff --git a/view/state/kind/locator/options.go b/view/state/kind/locator/options.go index d591e8666..9cf99b2eb 100644 --- a/view/state/kind/locator/options.go +++ b/view/state/kind/locator/options.go @@ -21,12 +21,13 @@ import ( // Options represents locator options type ( Options struct { - request *http.Request - Form *hstate.Form - Path map[string]string - Query url.Values - Header http.Header - Body []byte + request *http.Request + Form *hstate.Form + QuerySelectors hstate.QuerySelectors + Path map[string]string + Query url.Values + Header http.Header + Body []byte fromError error Parent *KindLocator @@ -181,6 +182,12 @@ func WithInputParameters(parameters state.NamedParameters) Option { } } +func WithQuerySelectors(selectors hstate.QuerySelectors) Option { + return func(o *Options) { + o.QuerySelectors = selectors + } +} + // WithPathParameters create with path parameters options func WithPathParameters(parameters map[string]string) Option { return func(o *Options) { From f09ab1ff9144f503e07471821ca358a0ec3f938a Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 7 Oct 2025 07:41:48 -0700 Subject: [PATCH 040/117] expose marshallers, move queryselector to xdatly --- service.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/service.go b/service.go index 78d5acf85..08fc5eb05 100644 --- a/service.go +++ b/service.go @@ -8,14 +8,17 @@ import ( "github.com/viant/cloudless/async/mbus" "github.com/viant/datly/gateway" "github.com/viant/datly/repository" + rcontent "github.com/viant/datly/repository/content" "github.com/viant/datly/repository/contract" "github.com/viant/datly/repository/locator/component/dispatcher" + srv "github.com/viant/datly/service" sjwt "github.com/viant/datly/service/auth/jwt" "github.com/viant/datly/service/auth/mock" "github.com/viant/datly/service/executor" "github.com/viant/datly/service/operator" "github.com/viant/datly/service/reader" "github.com/viant/datly/service/session" + "github.com/viant/datly/shared" "github.com/viant/datly/view" "github.com/viant/datly/view/extension" "github.com/viant/datly/view/state/kind/locator" @@ -282,6 +285,67 @@ func (s *Service) PopulateInput(ctx context.Context, aComponent *repository.Comp return nil } +// GetMarshaller prepares a request-scoped marshaller closure and resolved content type for the given component path. +// It preserves existing behavior for readers (format derived from query) and defaults to JSON otherwise. +func (s *Service) GetMarshaller(r *http.Request, methodAndPath string, extra ...repository.MarshalOption) (marshal shared.Marshal, contentType string, comp *repository.Component, err error) { + comp, err = s.Component(r.Context(), methodAndPath) + if err != nil || comp == nil { + if err == nil { + err = fmt.Errorf("component not found: %s", methodAndPath) + } + return nil, "", nil, err + } + + // Build component session to populate state (for exclusion filters) + sess := s.NewComponentSession(comp, WithRequest(r), WithStateResource(comp.View.Resource())) + // Compute JSON field filters from populated state + filters := comp.Exclusion(sess.State()) + + // Optional format override from query parameter `format` + override := strings.TrimSpace(r.URL.Query().Get("format")) + + var opts []repository.MarshalOption + opts = append(opts, repository.WithRequest(r), repository.WithFilters(filters)) + if override != "" { + opts = append(opts, repository.WithFormat(override)) + } + if len(extra) > 0 { + opts = append(opts, extra...) + } + + // Prepare marshaller closure + marshal = comp.MarshalFunc(opts...) + + // Resolve content type for headers + resolved := override + if resolved == "" && comp.Service == srv.TypeReader { + resolved = comp.Output.Format(r.URL.Query()) + } + if resolved == "" { + resolved = rcontent.JSONFormat + } + contentType = comp.Output.ContentType(resolved) + return marshal, contentType, comp, nil +} + +// GetUnmarshaller prepares a request-scoped unmarshaller for the given component path. +func (s *Service) GetUnmarshaller(r *http.Request, methodAndPath string, extra ...repository.UnmarshalOption) (unmarshal shared.Unmarshal, comp *repository.Component, err error) { + comp, err = s.Component(r.Context(), methodAndPath) + if err != nil || comp == nil { + if err == nil { + err = fmt.Errorf("component not found: %s", methodAndPath) + } + return nil, nil, err + } + var opts []repository.UnmarshalOption + opts = append(opts, repository.WithUnmarshalRequest(r)) + if len(extra) > 0 { + opts = append(opts, extra...) + } + unmarshal = comp.UnmarshalFor(opts...) + return unmarshal, comp, nil +} + // Read reads data from a view func (s *Service) Read(ctx context.Context, locator string, dest interface{}, option ...reader.Option) error { aView, err := s.View(ctx, wrapWithMethod(http.MethodGet, locator)) From 217831c16c85c2684e354786962b05b104308cad Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 7 Oct 2025 08:17:01 -0700 Subject: [PATCH 041/117] expose marshallers, move queryselector to xdatly --- .../router/marshal/json/marshaller_struct.go | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/gateway/router/marshal/json/marshaller_struct.go b/gateway/router/marshal/json/marshaller_struct.go index 23e2392a3..e3d962191 100644 --- a/gateway/router/marshal/json/marshaller_struct.go +++ b/gateway/router/marshal/json/marshaller_struct.go @@ -1,16 +1,18 @@ package json import ( + "reflect" + "strings" + "unicode" + "unsafe" + "github.com/francoispqt/gojay" "github.com/viant/datly/gateway/router/marshal/config" + "github.com/viant/datly/view/tags" structology "github.com/viant/structology" "github.com/viant/tagly/format" "github.com/viant/tagly/format/text" xunsafe "github.com/viant/xunsafe" - "reflect" - "strings" - "unicode" - "unsafe" ) type ( @@ -254,6 +256,15 @@ func (s *structMarshaller) createStructMarshallers(fields *groupedFields, path s if err != nil { return nil, err } + if dTag.Name == "" { //fallback to parameter + if parameterTag := field.Tag.Get("parameter"); parameterTag != "" { + if aTag, _ := tags.Parse(field.Tag, nil, tags.ParameterTag); aTag != nil && aTag.Parameter != nil { + if aTag.Parameter.Kind == "body" { + dTag.Name = aTag.Parameter.In + } + } + } + } elemType := field.Type // Unwrap nested pointers/slices to detect self-references like []*T or [][]*T @@ -315,6 +326,7 @@ func (s *structMarshaller) newFieldMarshaller(marshallers *[]*marshallerWithFiel } else if s.config.CaseFormat != "" { jsonName = formatName(jsonName, s.config.CaseFormat) } + path, outputPath = addToPath(path, field.Name), addToPath(outputPath, jsonName) xField := xunsafe.NewField(field) From 672e82b7059aa4efea643e93c275708e4ce019cf Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 8 Oct 2025 09:37:27 -0700 Subject: [PATCH 042/117] added generic router --- go.mod | 1 + router.go | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++ service.go | 56 ++++++++++++++++++++++-- 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 router.go diff --git a/go.mod b/go.mod index 4aa5d5121..7af2f0c20 100644 --- a/go.mod +++ b/go.mod @@ -165,3 +165,4 @@ require ( modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.0 // indirect ) + diff --git a/router.go b/router.go new file mode 100644 index 000000000..5e556376e --- /dev/null +++ b/router.go @@ -0,0 +1,125 @@ +package datly + +import ( + "context" + "errors" + "fmt" + "net/http" + "strconv" + + "github.com/viant/datly/repository" + "github.com/viant/datly/repository/contract" + "github.com/viant/xdatly/handler/response" + hstate "github.com/viant/xdatly/handler/state" +) + +type Handler[T any] func(ctx context.Context, service T, request *http.Request, injector hstate.Injector, extra ...OperateOption) (interface{}, error) + +type Route[T any] struct { + dao *Service + handler Handler[T] + service T + path *contract.Path + component *repository.Component +} + +func (r Route[T]) ensureComponent(ctx context.Context) (*repository.Component, error) { + if r.component == nil { + var err error + r.component, err = r.dao.repository.Registry().Lookup(ctx, r.path) + if err != nil { + return nil, err + } + } + return r.component, nil +} + +func (r Route[T]) Run(ctx context.Context, writer http.ResponseWriter, request *http.Request) error { + marshaller, contentType, _, err := r.dao.getMarshaller(request, r.component) + if err != nil { + return fmt.Errorf("failed to lookup marshaller: %w", err) + } + injector, err := r.dao.GetInjector(request, r.component) + if err != nil { + return fmt.Errorf("failed to lookup injector: %w", err) + } + selectors := []*hstate.NamedQuerySelector{} + values := request.URL.Query() + if page := values.Get("page"); page != "" { + selector := &hstate.NamedQuerySelector{Name: r.component.View.Name} + selector.Page, _ = strconv.Atoi(page) + selectors = append(selectors, selector) + } + result, err := r.handler(ctx, r.service, request, injector, WithSessionOptions(WithRequest(request), WithQuerySelectors(selectors...))) + var data []byte + if err != nil { + rErr, ok := err.(*response.Error) + if !ok { + rErr = response.NewError(http.StatusInternalServerError, err.Error()) + } + data, err = marshaller(rErr) + } else { + data, err = marshaller(result) + } + if err != nil { + http.Error(writer, err.Error(), http.StatusInternalServerError) + return nil + } + statusCode := http.StatusOK + statusCoder, ok := result.(response.StatusCoder) + if ok { + statusCode = statusCoder.StatusCode() + } + + writer.Header().Set("Content-Type", contentType) + writer.WriteHeader(statusCode) + _, err = writer.Write(data) + return err +} + +func newRoute[T any](dao *Service, path *contract.Path, component *repository.Component, service T, handler Handler[T]) *Route[T] { + return &Route[T]{path: path, handler: handler, dao: dao, component: component, service: service} +} + +type Router[T any] struct { + registry map[string]*Route[T] + dao *Service + service T +} + +type routeNotFound struct { + error +} + +// IsRouteNotFound checks if error is route not found +func IsRouteNotFound(err error) bool { + _, ok := err.(*routeNotFound) + return ok +} + +func (r *Router[T]) Run(writer http.ResponseWriter, request *http.Request) error { + aPath := contract.NewPath(request.Method, request.URL.Path) + component, err := r.dao.repository.Registry().Lookup(request.Context(), aPath) + if err != nil { + return &routeNotFound{err} + } + route, ok := r.registry[component.Path.Key()] + if !ok { + return &routeNotFound{errors.New("route not found")} + } + return route.Run(request.Context(), writer, request) +} + +func (r *Router[T]) Register(ctx context.Context, path *contract.Path, handler Handler[T]) error { + component, err := r.dao.repository.Registry().Lookup(ctx, path) + if err != nil { + return fmt.Errorf("failed to lookup component: %w for path: %+v", err, path) + } + route := newRoute[T](r.dao, path, component, r.service, handler) + r.registry[path.Key()] = route + return nil +} + +func NewRouter[T any](dao *Service, service T) *Router[T] { + return &Router[T]{registry: make(map[string]*Route[T]), dao: dao, service: service} +} diff --git a/service.go b/service.go index 08fc5eb05..1b67c0847 100644 --- a/service.go +++ b/service.go @@ -285,6 +285,15 @@ func (s *Service) PopulateInput(ctx context.Context, aComponent *repository.Comp return nil } +func (s *Service) GetInjector(r *http.Request, comp *repository.Component) (hstate.Injector, error) { + if err := s.ensureComponentInitialized(comp); err != nil { + return nil, err + } + // Build component session to populate state (for exclusion filters) + sess := s.NewComponentSession(comp, WithRequest(r), WithStateResource(comp.View.Resource())) + return sess, nil +} + // GetMarshaller prepares a request-scoped marshaller closure and resolved content type for the given component path. // It preserves existing behavior for readers (format derived from query) and defaults to JSON otherwise. func (s *Service) GetMarshaller(r *http.Request, methodAndPath string, extra ...repository.MarshalOption) (marshal shared.Marshal, contentType string, comp *repository.Component, err error) { @@ -295,6 +304,14 @@ func (s *Service) GetMarshaller(r *http.Request, methodAndPath string, extra ... } return nil, "", nil, err } + return s.getMarshaller(r, comp, extra...) +} + +func (s *Service) getMarshaller(r *http.Request, comp *repository.Component, extra ...repository.MarshalOption) (shared.Marshal, string, *repository.Component, error) { + // Ensure component content marshallers are initialized (defensive when invoked outside router lifecycle) + if err := s.ensureComponentInitialized(comp); err != nil { + return nil, "", nil, err + } // Build component session to populate state (for exclusion filters) sess := s.NewComponentSession(comp, WithRequest(r), WithStateResource(comp.View.Resource())) @@ -314,7 +331,7 @@ func (s *Service) GetMarshaller(r *http.Request, methodAndPath string, extra ... } // Prepare marshaller closure - marshal = comp.MarshalFunc(opts...) + marshal := comp.MarshalFunc(opts...) // Resolve content type for headers resolved := override @@ -324,7 +341,7 @@ func (s *Service) GetMarshaller(r *http.Request, methodAndPath string, extra ... if resolved == "" { resolved = rcontent.JSONFormat } - contentType = comp.Output.ContentType(resolved) + contentType := comp.Output.ContentType(resolved) return marshal, contentType, comp, nil } @@ -337,15 +354,46 @@ func (s *Service) GetUnmarshaller(r *http.Request, methodAndPath string, extra . } return nil, nil, err } + return s.getUnmarshaller(r, comp, extra...) +} + +func (s *Service) getUnmarshaller(r *http.Request, comp *repository.Component, extra ...repository.UnmarshalOption) (shared.Unmarshal, *repository.Component, error) { + // Ensure component content marshallers are initialized (defensive) + if err := s.ensureComponentInitialized(comp); err != nil { + return nil, nil, err + } var opts []repository.UnmarshalOption opts = append(opts, repository.WithUnmarshalRequest(r)) if len(extra) > 0 { opts = append(opts, extra...) } - unmarshal = comp.UnmarshalFor(opts...) + unmarshal := comp.UnmarshalFor(opts...) return unmarshal, comp, nil } +// ensureComponentInitialized defensively initializes component content marshallers when called from external contexts. +func (s *Service) ensureComponentInitialized(comp *repository.Component) error { + if comp == nil { + return fmt.Errorf("component was nil") + } + res := comp.View.GetResource() + if res == nil { + return nil + } + // If JSON marshaller already present, assume initialized. + if comp.Content.Marshaller.JSON.JsonMarshaller != nil { + return nil + } + // Initialize content marshallers as in Component.Init + if err := comp.Content.InitMarshaller(comp.IOConfig(), comp.Output.Exclude, comp.BodyType(), comp.OutputType()); err != nil { + return err + } + if err := comp.Content.Marshaller.Init(res.LookupType()); err != nil { + return err + } + return nil +} + // Read reads data from a view func (s *Service) Read(ctx context.Context, locator string, dest interface{}, option ...reader.Option) error { aView, err := s.View(ctx, wrapWithMethod(http.MethodGet, locator)) @@ -595,7 +643,7 @@ func (s *Service) HTTPHandler(ctx context.Context, options ...gateway.Option) (h return s.handler, nil } -// New creates a datly service, repository allows you to bootstrap empty or existing yaml repository +// New creates a dao dao, repository allows you to bootstrap empty or existing yaml repository func New(ctx context.Context, options ...repository.Option) (*Service, error) { options = append([]repository.Option{ repository.WithJWTSigner(mock.HmacJwtSigner()), From 1a97134326b303d66d19a251fba34c6acac226a6 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 8 Oct 2025 10:20:48 -0700 Subject: [PATCH 043/117] added generic router --- service.go | 1 + service/session/stater.go | 35 +++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/service.go b/service.go index 1b67c0847..32a2cdcc4 100644 --- a/service.go +++ b/service.go @@ -179,6 +179,7 @@ func (s *Service) NewComponentSession(aComponent *repository.Component, opts ... } aSession := session.New(aComponent.View, session.WithLocatorOptions(options...), session.WithAuth(s.repository.Auth()), + session.WithComponent(aComponent), session.WithStateResource(sessionOpt.resource), session.WithOperate(s.operator.Operate)) return aSession } diff --git a/service/session/stater.go b/service/session/stater.go index d2bda7a34..a98548014 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -7,6 +7,8 @@ import ( "reflect" "runtime/debug" + "embed" + "github.com/viant/datly/utils/types" "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind/locator" @@ -55,12 +57,33 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt destType := reflect.TypeOf(dest) sType := types.EnsureStruct(destType) stateType, ok := s.Types.Lookup(sType) - if !ok { - if stateType, err = state.NewType( - state.WithSchema(state.NewSchema(destType)), - state.WithResource(s.resource), - ); err != nil { - return err + + var embedFs *embed.FS + if embedder, ok := dest.(state.Embedder); ok { + embedFs = embedder.EmbedFS() + } + + if !ok && s.component != nil { + + if s.component.Input.Type.Type() != nil { + if destType == s.component.Input.Type.Type().Type() { + stateType = &s.component.Input.Type + } + } + if s.component.Output.Type.Type() != nil { + if destType == s.component.Output.Type.Type().Type() { + stateType = &s.component.Output.Type + } + } + + if stateType == nil { + if stateType, err = state.NewType( + state.WithSchema(state.NewSchema(destType)), + state.WithResource(s.resource), + state.WithFS(embedFs), + ); err != nil { + return err + } } s.Types.Put(stateType) } From a0ec4c34db4d347bee5d965e8b8acb4dc99391ad Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 8 Oct 2025 12:50:53 -0700 Subject: [PATCH 044/117] updated locator signature --- repository/locator/async/locator.go | 3 +- repository/locator/component/component.go | 2 +- repository/locator/meta/locator.go | 3 +- repository/locator/output/output.go | 3 +- router.go | 1 + service/executor/handler/locator/handler.go | 3 +- service/session/state.go | 5 +- view/state/kind/locator.go | 4 +- view/state/kind/locator/body.go | 54 +++++++++++++-------- view/state/kind/locator/constants.go | 3 +- view/state/kind/locator/context.go | 3 +- view/state/kind/locator/cookie.go | 3 +- view/state/kind/locator/data.go | 2 +- view/state/kind/locator/env.go | 3 +- view/state/kind/locator/form.go | 3 +- view/state/kind/locator/generator.go | 3 +- view/state/kind/locator/header.go | 3 +- view/state/kind/locator/http.go | 3 +- view/state/kind/locator/object.go | 3 +- view/state/kind/locator/parameter.go | 3 +- view/state/kind/locator/path.go | 3 +- view/state/kind/locator/query.go | 3 +- view/state/kind/locator/repeated.go | 2 +- view/state/kind/locator/state.go | 3 +- view/state/kind/locator/transient.go | 3 +- 25 files changed, 81 insertions(+), 43 deletions(-) diff --git a/repository/locator/async/locator.go b/repository/locator/async/locator.go index bc8141cde..7d047fe42 100644 --- a/repository/locator/async/locator.go +++ b/repository/locator/async/locator.go @@ -9,13 +9,14 @@ import ( "github.com/viant/xdatly/handler/async" "github.com/viant/xdatly/handler/exec" "github.com/viant/xdatly/handler/response" + "reflect" "strings" "time" ) type Locator struct{} -func (l *Locator) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (l *Locator) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { name = strings.ToLower(name) if name == keys.JobError { diff --git a/repository/locator/component/component.go b/repository/locator/component/component.go index 9fd8f6dea..b38907df6 100644 --- a/repository/locator/component/component.go +++ b/repository/locator/component/component.go @@ -35,7 +35,7 @@ func (l *componentLocator) Names() []string { return nil } -func (l *componentLocator) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (l *componentLocator) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { method, URI := shared.ExtractPath(name) request, err := l.getRequest() if err != nil { diff --git a/repository/locator/meta/locator.go b/repository/locator/meta/locator.go index 487a58be8..ba1b0c1af 100644 --- a/repository/locator/meta/locator.go +++ b/repository/locator/meta/locator.go @@ -7,13 +7,14 @@ import ( "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind" "github.com/viant/datly/view/state/kind/locator" + "reflect" "strings" ) type metaLocator struct { } -func (l *metaLocator) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (l *metaLocator) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { value := ctx.Value(view.ContextKey) if value == nil { return nil, false, nil diff --git a/repository/locator/output/output.go b/repository/locator/output/output.go index c9368971a..ec6b3ed5f 100644 --- a/repository/locator/output/output.go +++ b/repository/locator/output/output.go @@ -3,6 +3,7 @@ package output import ( "context" "encoding/json" + "reflect" "strings" "github.com/viant/datly/repository/locator/output/keys" @@ -25,7 +26,7 @@ func (l *Locator) Names() []string { return nil } -func (l *Locator) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (l *Locator) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { aName := strings.ToLower(name) switch aName { case keys.ViewData: diff --git a/router.go b/router.go index 5e556376e..1117ee905 100644 --- a/router.go +++ b/router.go @@ -101,6 +101,7 @@ func (r *Router[T]) Run(writer http.ResponseWriter, request *http.Request) error aPath := contract.NewPath(request.Method, request.URL.Path) component, err := r.dao.repository.Registry().Lookup(request.Context(), aPath) if err != nil { + fmt.Println(err) return &routeNotFound{err} } route, ok := r.registry[component.Path.Key()] diff --git a/service/executor/handler/locator/handler.go b/service/executor/handler/locator/handler.go index 3758b8abd..6f0c31aeb 100644 --- a/service/executor/handler/locator/handler.go +++ b/service/executor/handler/locator/handler.go @@ -11,6 +11,7 @@ import ( "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind" "github.com/viant/datly/view/state/kind/locator" + "reflect" ) type Handler struct { @@ -22,7 +23,7 @@ func (v *Handler) Names() []string { return nil } -func (v *Handler) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (v *Handler) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { resource := v.options.Resource if resource == nil { return nil, false, fmt.Errorf("failed to lookup handler resource: %v", name) diff --git a/service/session/state.go b/service/session/state.go index f7b0e8ce5..8e6eab3f3 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -581,7 +581,8 @@ func (s *Session) lookupValue(ctx context.Context, parameter *state.Parameter, o if err != nil { return nil, false, fmt.Errorf("failed to locate parameter: %v, %w", parameter.Name, err) } - if value, has, err = parameterLocator.Value(ctx, parameter.In.Name); err != nil { + + if value, has, err = parameterLocator.Value(ctx, parameter.OutputType(), parameter.In.Name); err != nil { return nil, false, err } if parameter.In.Kind == state.KindConst && !has { //if parameter is const and has no value, use default value @@ -596,7 +597,7 @@ func (s *Session) lookupValue(ctx context.Context, parameter *state.Parameter, o if err != nil { return nil, false, fmt.Errorf("failed to locate parameter: %v, %w", baseParameter.Name, err) } - if value, has, err = parameterLocator.Value(ctx, baseParameter.In.Name); err != nil { + if value, has, err = parameterLocator.Value(ctx, baseParameter.OutputType(), baseParameter.In.Name); err != nil { return nil, false, err } } diff --git a/view/state/kind/locator.go b/view/state/kind/locator.go index 57f765f0e..864d85b00 100644 --- a/view/state/kind/locator.go +++ b/view/state/kind/locator.go @@ -2,6 +2,8 @@ package kind import ( "context" + "reflect" + "github.com/viant/datly/view/state" ) @@ -9,7 +11,7 @@ import ( type Locator interface { //Value returns parameter value - Value(ctx context.Context, name string) (interface{}, bool, error) + Value(ctx context.Context, rType reflect.Type, name string) (interface{}, bool, error) //Names returns names of supported parameters Names() []string diff --git a/view/state/kind/locator/body.go b/view/state/kind/locator/body.go index fc41a49aa..b80d112dd 100644 --- a/view/state/kind/locator/body.go +++ b/view/state/kind/locator/body.go @@ -27,16 +27,32 @@ func (r *Body) Names() []string { return nil } -func (r *Body) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (r *Body) Value(ctx context.Context, rType reflect.Type, name string) (interface{}, bool, error) { var err error + r.Once.Do(func() { var request *http.Request request, r.err = shared.CloneHTTPRequest(r.request) r.body, r.err = readRequestBody(request) - if len(r.body) > 0 { - r.err = r.ensureRequest() - } + }) + + var requestState *structology.State + + if len(r.body) > 0 { + if r.requestState != nil && r.requestState.Type().Type() == rType { + requestState = r.requestState + } + if name == "" { + requestState, r.err = r.ensureRequest(rType) + } else { + requestState, r.err = r.ensureRequest(r.bodyType) + } + if r.err == nil { + r.requestState = requestState + } + } + if len(r.body) == 0 { return nil, false, nil } @@ -47,16 +63,16 @@ func (r *Body) Value(ctx context.Context, name string) (interface{}, bool, error return r.decodeBodyMap(ctx) } if name == "" { - return r.requestState.State(), true, nil + return requestState.State(), true, nil } - sel, err := r.requestState.Selector(name) + sel, err := requestState.Selector(name) if err != nil { return nil, false, err } - if !sel.Has(r.requestState.Pointer()) { + if !sel.Has(requestState.Pointer()) { return nil, false, nil } - return sel.Value(r.requestState.Pointer()), true, nil + return sel.Value(requestState.Pointer()), true, nil } func (r *Body) decodeBodyMap(ctx context.Context) (interface{}, bool, error) { @@ -87,21 +103,21 @@ func NewBody(opts ...Option) (kind.Locator, error) { return ret, nil } -func (r *Body) ensureRequest() (err error) { - if r.bodyType == nil { - return nil +func (r *Body) ensureRequest(rType reflect.Type) (*structology.State, error) { + if rType == nil { + return nil, nil } - rType := r.bodyType if rType.Kind() == reflect.Map { - return nil + return nil, nil } - bodyType := structology.NewStateType(r.bodyType) - r.requestState = bodyType.NewState() - dest := r.requestState.StatePtr() - if err = r.unmarshal(r.body, dest); err == nil { - r.requestState.Sync() + bodyType := structology.NewStateType(rType) + requestState := bodyType.NewState() + dest := requestState.StatePtr() + err := r.unmarshal(r.body, dest) + if err == nil { + requestState.Sync() } - return err + return requestState, err } func (r *Body) updateQueryString(ctx context.Context, body interface{}) { diff --git a/view/state/kind/locator/constants.go b/view/state/kind/locator/constants.go index f6cd81eeb..516e7c4a2 100644 --- a/view/state/kind/locator/constants.go +++ b/view/state/kind/locator/constants.go @@ -3,6 +3,7 @@ package locator import ( "context" "github.com/viant/datly/view/state/kind" + "reflect" "sync" ) @@ -16,7 +17,7 @@ func (r *Constants) Names() []string { return nil } -func (r *Constants) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (r *Constants) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { if len(r.constants) > 0 { if value, ok := r.constants[name]; ok { return value, true, nil diff --git a/view/state/kind/locator/context.go b/view/state/kind/locator/context.go index d5fcd827c..33d0985c4 100644 --- a/view/state/kind/locator/context.go +++ b/view/state/kind/locator/context.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/viant/datly/view/state/kind" "github.com/viant/xdatly/handler/exec" + "reflect" ) type Context struct { @@ -14,7 +15,7 @@ func (v *Context) Names() []string { return nil } -func (v *Context) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (v *Context) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { rawValue := ctx.Value(exec.ContextKey) if rawValue == nil { diff --git a/view/state/kind/locator/cookie.go b/view/state/kind/locator/cookie.go index 804949592..117550935 100644 --- a/view/state/kind/locator/cookie.go +++ b/view/state/kind/locator/cookie.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/viant/datly/view/state/kind" "net/http" + "reflect" ) type Cookie struct { @@ -19,7 +20,7 @@ func (v *Cookie) Names() []string { return result } -func (v *Cookie) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (v *Cookie) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { for _, cookie := range v.cookies { if cookie.Name == name { return cookie.Value, true, nil diff --git a/view/state/kind/locator/data.go b/view/state/kind/locator/data.go index efcabfdb5..db35876c5 100644 --- a/view/state/kind/locator/data.go +++ b/view/state/kind/locator/data.go @@ -18,7 +18,7 @@ func (p *DataView) Names() []string { return nil } -func (p *DataView) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (p *DataView) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { aView, ok := p.Views[name] if !ok { return nil, false, fmt.Errorf("failed to lookup view: %v", name) diff --git a/view/state/kind/locator/env.go b/view/state/kind/locator/env.go index 05ccc5217..28b980e5d 100644 --- a/view/state/kind/locator/env.go +++ b/view/state/kind/locator/env.go @@ -4,6 +4,7 @@ import ( "context" "github.com/viant/datly/view/state/kind" "os" + "reflect" ) type Env struct { @@ -14,7 +15,7 @@ func (v *Env) Names() []string { return os.Environ() } -func (v *Env) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (v *Env) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { ret, ok := v.env[name] return ret, ok, nil } diff --git a/view/state/kind/locator/form.go b/view/state/kind/locator/form.go index 387815e79..174f66255 100644 --- a/view/state/kind/locator/form.go +++ b/view/state/kind/locator/form.go @@ -5,6 +5,7 @@ import ( "github.com/viant/datly/view/state/kind" "github.com/viant/xdatly/handler/state" "net/http" + "reflect" ) type Form struct { @@ -16,7 +17,7 @@ func (r *Form) Names() []string { return nil } -func (r *Form) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (r *Form) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { if r.form != nil && len(r.form.Values) == 0 && r.request == nil { return nil, false, nil } diff --git a/view/state/kind/locator/generator.go b/view/state/kind/locator/generator.go index 1583357f8..f020b40ff 100644 --- a/view/state/kind/locator/generator.go +++ b/view/state/kind/locator/generator.go @@ -4,6 +4,7 @@ import ( "context" "github.com/google/uuid" "github.com/viant/datly/view/state/kind" + "reflect" "strings" "time" ) @@ -14,7 +15,7 @@ func (v *Generator) Names() []string { return nil } -func (v *Generator) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (v *Generator) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { switch strings.ToLower(name) { case "nil": return nil, true, nil diff --git a/view/state/kind/locator/header.go b/view/state/kind/locator/header.go index e6a8135e2..c2fd3962f 100644 --- a/view/state/kind/locator/header.go +++ b/view/state/kind/locator/header.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/viant/datly/view/state/kind" "net/http" + "reflect" ) type Header struct { @@ -20,7 +21,7 @@ func (q *Header) Names() []string { return result } -func (q *Header) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (q *Header) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { value, ok := q.header[name] if !ok { return nil, false, nil diff --git a/view/state/kind/locator/http.go b/view/state/kind/locator/http.go index a2becfe56..8fdd0d9bc 100644 --- a/view/state/kind/locator/http.go +++ b/view/state/kind/locator/http.go @@ -7,6 +7,7 @@ import ( "github.com/viant/datly/view/state/kind" "io" "net/http" + "reflect" "strings" ) @@ -19,7 +20,7 @@ func (p *HttpRequest) Names() []string { return nil } -func (p *HttpRequest) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (p *HttpRequest) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { request := p.request if p.request == nil { var err error diff --git a/view/state/kind/locator/object.go b/view/state/kind/locator/object.go index f1c066718..ced3fe835 100644 --- a/view/state/kind/locator/object.go +++ b/view/state/kind/locator/object.go @@ -6,6 +6,7 @@ import ( "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind" "github.com/viant/structology" + "reflect" ) type Object struct { @@ -19,7 +20,7 @@ func (p *Object) Names() []string { return nil } -func (p *Object) Value(ctx context.Context, names string) (interface{}, bool, error) { +func (p *Object) Value(ctx context.Context, _ reflect.Type, names string) (interface{}, bool, error) { parameter := p.matchByLocation(names) if parameter == nil { return nil, false, fmt.Errorf("failed to match parameter by location: %v", names) diff --git a/view/state/kind/locator/parameter.go b/view/state/kind/locator/parameter.go index b46f54ed0..35578c13c 100644 --- a/view/state/kind/locator/parameter.go +++ b/view/state/kind/locator/parameter.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind" + "reflect" ) type Parameter struct { @@ -16,7 +17,7 @@ func (p *Parameter) Names() []string { return nil } -func (p *Parameter) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (p *Parameter) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { parameter, ok := p.Parameters[name] if !ok { return nil, false, fmt.Errorf("uknonw parameter: %s", name) diff --git a/view/state/kind/locator/path.go b/view/state/kind/locator/path.go index eecabec7c..79a8af548 100644 --- a/view/state/kind/locator/path.go +++ b/view/state/kind/locator/path.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/viant/datly/view/state/kind" "github.com/viant/toolbox" + "reflect" ) type Path struct { @@ -20,7 +21,7 @@ func (v *Path) Names() []string { return result } -func (v *Path) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (v *Path) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { if name == "" { return v.path, true, nil } diff --git a/view/state/kind/locator/query.go b/view/state/kind/locator/query.go index 605f1b1a7..b532215aa 100644 --- a/view/state/kind/locator/query.go +++ b/view/state/kind/locator/query.go @@ -7,6 +7,7 @@ import ( "github.com/viant/xdatly/handler/exec" "net/http" "net/url" + "reflect" ) type Query struct { @@ -23,7 +24,7 @@ func (q *Query) Names() []string { return result } -func (q *Query) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (q *Query) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { if name == "" { return q.rawQuery, true, nil } diff --git a/view/state/kind/locator/repeated.go b/view/state/kind/locator/repeated.go index 1d07fde50..2f19e91ae 100644 --- a/view/state/kind/locator/repeated.go +++ b/view/state/kind/locator/repeated.go @@ -28,7 +28,7 @@ func (p *Repeated) Names() []string { return nil } -func (p *Repeated) Value(ctx context.Context, names string) (interface{}, bool, error) { +func (p *Repeated) Value(ctx context.Context, _ reflect.Type, names string) (interface{}, bool, error) { parameter := p.matchByLocation(names) if parameter == nil { return nil, false, fmt.Errorf("failed to match parameter by location: %v", names) diff --git a/view/state/kind/locator/state.go b/view/state/kind/locator/state.go index bbd44cd4c..503dba3f5 100644 --- a/view/state/kind/locator/state.go +++ b/view/state/kind/locator/state.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/viant/datly/view/state/kind" "github.com/viant/structology" + "reflect" ) type State struct { @@ -14,7 +15,7 @@ type State struct { func (p *State) Names() []string { return nil } -func (p *State) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (p *State) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { _, err := p.State.Selector(name) if err != nil { return nil, false, nil diff --git a/view/state/kind/locator/transient.go b/view/state/kind/locator/transient.go index 0fde22e6e..72ac34cca 100644 --- a/view/state/kind/locator/transient.go +++ b/view/state/kind/locator/transient.go @@ -3,6 +3,7 @@ package locator import ( "context" "github.com/viant/datly/view/state/kind" + "reflect" ) type Transient struct{} @@ -11,7 +12,7 @@ func (v *Transient) Names() []string { return nil } -func (v *Transient) Value(ctx context.Context, name string) (interface{}, bool, error) { +func (v *Transient) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { if name == "" { return nil, false, nil } From 9972471896cc58ee1e255ac1ef1f1bab94e846b9 Mon Sep 17 00:00:00 2001 From: vc42 Date: Thu, 9 Oct 2025 13:39:06 -0400 Subject: [PATCH 045/117] allow large json objects in LoadData --- view/extension/handler/loader.go | 81 +++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/view/extension/handler/loader.go b/view/extension/handler/loader.go index 7dd4fc96f..86a5966c2 100644 --- a/view/extension/handler/loader.go +++ b/view/extension/handler/loader.go @@ -6,6 +6,7 @@ import ( "compress/gzip" "context" "encoding/json" + "errors" "fmt" "github.com/viant/afs" "github.com/viant/datly/utils/types" @@ -42,56 +43,92 @@ func (l *LoadData) Exec(ctx context.Context, session handler.Session) (interface if !ok || err != nil { return nil, fmt.Errorf("invalid Loader URL: %w", err) } + var URL string - switch URLValue.(type) { + switch v := URLValue.(type) { case string: - URL = URLValue.(string) + URL = v case *string: - URL = *URLValue.(*string) + URL = *v default: - return nil, fmt.Errorf("invalid Loader URL: expected %T, but had %T", URL, URLValue) + return nil, fmt.Errorf("invalid Loader URL: expected %T, but had %T", "", URLValue) } + // Prefer .gz if the plain URL doesn't exist. if ok, _ := l.fs.Exists(ctx, URL); !ok { if ok, _ := l.fs.Exists(ctx, URL+".gz"); ok { URL += ".gz" } } - isCompressed := strings.HasSuffix(URL, ".gz") + // Download compressed or plain bytes (API returns []byte). data, err := l.fs.DownloadWithURL(ctx, URL) if err != nil { return nil, fmt.Errorf("failed to load URL: %w", err) } - if isCompressed { - reader, err := gzip.NewReader(bytes.NewReader(data)) + + // Build a streaming reader chain; avoid io.ReadAll on gzip. + var r io.Reader = bytes.NewReader(data) + if strings.HasSuffix(URL, ".gz") { + gzr, err := gzip.NewReader(r) if err != nil { return nil, fmt.Errorf("failed to decompress URL: failed to create reader: %w (used URL: %s)", err, URL) } - defer reader.Close() - if data, err = io.ReadAll(reader); err != nil { - return nil, fmt.Errorf("failed to decompress URL:%w (used URL: %s)", err, URL) - } + defer gzr.Close() + r = gzr } + + br := bufio.NewReaderSize(r, 1<<20) // read-ahead; does NOT cap JSON size + dec := json.NewDecoder(br) + dec.UseNumber() + + // Output slice + appender (kept from your original design) itemType := l.Options.OutputType.Elem() xSlice := xunsafe.NewSlice(l.Options.OutputType) - scanner := bufio.NewScanner(bytes.NewReader(data)) response := reflect.New(l.Options.OutputType).Interface() appender := xSlice.Appender(xunsafe.AsPointer(response)) - scanner.Buffer(make([]byte, 1024*1024), 5*1024*1024) - for scanner.Scan() { - line := scanner.Bytes() - if len(line) == 0 { - continue + + // Reject top-level arrays to keep the code simple (no streaming array parsing). + first, err := peekFirstNonSpace(br) + if err != nil { + if errors.Is(err, io.EOF) { + return response, nil // empty file -> empty slice } - item := types.NewValue(itemType) - err := json.Unmarshal(scanner.Bytes(), item) - if err != nil { - return nil, fmt.Errorf("invalid item: %w, %s", err, line) + return nil, fmt.Errorf("read error: %w", err) + } + if first == '[' { + return nil, fmt.Errorf("top-level JSON arrays are not supported; provide NDJSON (one object per line) or a single JSON object") + } + // Put the byte back so the decoder sees it. + _ = br.UnreadByte() + + // Decode one value per call: supports single object or NDJSON. + for { + item := types.NewValue(itemType) // pointer to zero value of element type + if err := dec.Decode(item); err != nil { + if errors.Is(err, io.EOF) { + break + } + return nil, fmt.Errorf("invalid item: %w", err) } appender.Append(item) } - return response, scanner.Err() + + return response, nil +} + +// Reads and returns the first non-space byte without consuming input for the decoder. +func peekFirstNonSpace(br *bufio.Reader) (byte, error) { + for { + b, err := br.ReadByte() + if err != nil { + return 0, err + } + if b == ' ' || b == '\n' || b == '\r' || b == '\t' { + continue + } + return b, nil + } } func (*LoadDataProvider) New(ctx context.Context, opts ...handler.Option) (handler.Handler, error) { From ad9cc45d85d05f7157f0ff01912745a8e2c166e5 Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 9 Oct 2025 13:57:41 -0700 Subject: [PATCH 046/117] updated locator signature --- router.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/router.go b/router.go index 1117ee905..03504a4eb 100644 --- a/router.go +++ b/router.go @@ -124,3 +124,7 @@ func (r *Router[T]) Register(ctx context.Context, path *contract.Path, handler H func NewRouter[T any](dao *Service, service T) *Router[T] { return &Router[T]{registry: make(map[string]*Route[T]), dao: dao, service: service} } + +type BodyEnvelope[T any] struct { + Body T `parameter:",kind=body"` +} From a5e53061cbf1ef11ee28db6c7b66b72e1b420c6d Mon Sep 17 00:00:00 2001 From: vc42 Date: Sun, 12 Oct 2025 08:21:55 -0400 Subject: [PATCH 047/117] fixed concurrency issues in deferredMarshaller --- gateway/router/marshal/json/cache.go | 20 ++++----- .../marshal/json/marshaller_deferred.go | 42 +++++++++++++++---- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/gateway/router/marshal/json/cache.go b/gateway/router/marshal/json/cache.go index 728af816d..d08a4704f 100644 --- a/gateway/router/marshal/json/cache.go +++ b/gateway/router/marshal/json/cache.go @@ -100,25 +100,23 @@ func (m *marshallersCache) loadMarshaller(rType reflect.Type, config *config.IOC return marshaller, nil } -func (c *pathCache) loadOrGetMarshaller(rType reflect.Type, config *config.IOConfig, path string, outputPath string, tag *format.Tag, options ...interface{}) (marshaler, error) { - value, ok := c.cache.Load(rType) +func (c *pathCache) loadOrGetMarshaller(rType reflect.Type, cfg *config.IOConfig, path, outPath string, tag *format.Tag, options ...interface{}) (marshaler, error) { + + placeholder := newDeferred() + value, ok := c.cache.LoadOrStore(rType, placeholder) if ok { return value.(marshaler), nil } - // Place a deferred placeholder to break recursive graphs for this path and type. - placeholder := &deferredMarshaller{} - c.storeMarshaler(rType, placeholder) - - aMarshaler, err := c.getMarshaller(rType, config, path, outputPath, tag, options...) + aMarshaller, err := c.getMarshaller(rType, cfg, path, outPath, tag, options...) if err != nil { + placeholder.fail(err) // unblock anyone holding the promise + c.cache.CompareAndDelete(rType, placeholder) // allow a clean retry later return nil, err } - // Swap placeholder with the real marshaller and set target for any users that captured it. - placeholder.setTarget(aMarshaler) - c.storeMarshaler(rType, aMarshaler) - return aMarshaler, nil + placeholder.setTarget(aMarshaller) // resolve success + return aMarshaller, nil } func (c *pathCache) getMarshaller(rType reflect.Type, config *config.IOConfig, path string, outputPath string, tag *format.Tag, options ...interface{}) (marshaler, error) { diff --git a/gateway/router/marshal/json/marshaller_deferred.go b/gateway/router/marshal/json/marshaller_deferred.go index fef24a83d..48955de80 100644 --- a/gateway/router/marshal/json/marshaller_deferred.go +++ b/gateway/router/marshal/json/marshaller_deferred.go @@ -2,30 +2,56 @@ package json import ( "fmt" - "github.com/francoispqt/gojay" "unsafe" + + "github.com/francoispqt/gojay" ) // deferredMarshaller is a placeholder used to break recursive type graphs during construction. // It forwards calls to the actual target once it is set. type deferredMarshaller struct { target marshaler + ready chan struct{} + err error +} + +func newDeferred() *deferredMarshaller { + return &deferredMarshaller{ready: make(chan struct{})} } func (d *deferredMarshaller) setTarget(m marshaler) { d.target = m + close(d.ready) +} + +func (d *deferredMarshaller) fail(e error) { + d.err = e + close(d.ready) // writes to err happen-before any receive on ready } -func (d *deferredMarshaller) MarshallObject(ptr unsafe.Pointer, session *MarshallSession) error { +func (d *deferredMarshaller) resolved() (marshaler, error) { + <-d.ready // wait for resolve/fail + if d.err != nil { + return nil, d.err + } if d.target == nil { - return fmt.Errorf("marshaller not initialized") + return nil, fmt.Errorf("marshaller not initialized") } - return d.target.MarshallObject(ptr, session) + return d.target, nil } -func (d *deferredMarshaller) UnmarshallObject(pointer unsafe.Pointer, decoder *gojay.Decoder, auxiliaryDecoder *gojay.Decoder, session *UnmarshalSession) error { - if d.target == nil { - return fmt.Errorf("marshaller not initialized") +func (d *deferredMarshaller) MarshallObject(ptr unsafe.Pointer, s *MarshallSession) error { + m, err := d.resolved() + if err != nil { + return err + } + return m.MarshallObject(ptr, s) +} + +func (d *deferredMarshaller) UnmarshallObject(p unsafe.Pointer, dec, aux *gojay.Decoder, s *UnmarshalSession) error { + m, err := d.resolved() + if err != nil { + return err } - return d.target.UnmarshallObject(pointer, decoder, auxiliaryDecoder, session) + return m.UnmarshallObject(p, dec, aux, s) } From 71810a809d693135c81fbb58ac56d5e3f1d990c2 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 15 Oct 2025 12:15:38 -0700 Subject: [PATCH 048/117] updated locator signature --- service/executor/expand/data_unit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/executor/expand/data_unit.go b/service/executor/expand/data_unit.go index 784953fc9..9d2c22dad 100644 --- a/service/executor/expand/data_unit.go +++ b/service/executor/expand/data_unit.go @@ -148,7 +148,7 @@ func (c *DataUnit) Next() (interface{}, error) { return c.ParamsGroup[index], nil } - return nil, fmt.Errorf("expected to get binding parameter, but noone was found, ParamsGroup: %v, placeholderCounter: %v", c.ParamsGroup, c.placeholderCounter) + return nil, fmt.Errorf("expected to get binding parameter, but none was found, ParamsGroup: %v, placeholderCounter: %v", c.ParamsGroup, c.placeholderCounter) } func (c *DataUnit) ensureSliceIndex() { From cca251ddc956c026cb2140655ebb24f95d4c56d6 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 20 Oct 2025 09:17:34 -0700 Subject: [PATCH 049/117] enhanced mcp integration --- gateway/mcp.go | 327 +++++++++++++----- gateway/router/marshal/json/marshaller_map.go | 9 +- .../router/marshal/json/marshaller_strings.go | 49 ++- go.mod | 5 +- go.sum | 10 +- repository/component.go | 103 ++++++ 6 files changed, 397 insertions(+), 106 deletions(-) diff --git a/gateway/mcp.go b/gateway/mcp.go index 45310d541..0a9624afe 100644 --- a/gateway/mcp.go +++ b/gateway/mcp.go @@ -4,6 +4,12 @@ import ( "context" "encoding/json" "fmt" + "io" + "net/http" + "net/url" + "reflect" + "strings" + furl "github.com/viant/afs/url" "github.com/viant/datly/gateway/router/proxy" "github.com/viant/datly/repository" @@ -14,11 +20,6 @@ import ( "github.com/viant/mcp-protocol/schema" serverproto "github.com/viant/mcp-protocol/server" "github.com/viant/toolbox" - "io" - "net/http" - "net/url" - "reflect" - "strings" ) func (r *Router) buildToolsIntegration(item *dpath.Item, aPath *dpath.Path, aRoute *Route, provider *repository.Provider) error { @@ -53,109 +54,188 @@ func (r *Router) buildToolsIntegration(item *dpath.Item, aPath *dpath.Path, aRou } func (r *Router) mcpToolCallHandler(component *repository.Component, aRoute *Route) serverproto.ToolHandlerFunc { - handler := func(ctx context.Context, req *schema.CallToolRequest) (*schema.CallToolResult, *jsonrpc.Error) { + return func(ctx context.Context, req *schema.CallToolRequest) (*schema.CallToolResult, *jsonrpc.Error) { params := req.Params - URI := r.matchToolCallComponentURI(aRoute, component, params) - URL := fmt.Sprintf("http://localhost/%v", strings.TrimLeft(URI, "/")) // fallback to a local URL for now, this should be replaced with the actual service URL + uri := r.matchToolCallComponentURI(aRoute, component, params) + baseURL := fmt.Sprintf("http://localhost/%v", strings.TrimLeft(uri, "/")) // replace with actual service URL when available + values := url.Values{} var body io.Reader - var uniquePath = make(map[string]bool) - var uniqueQuery = make(map[string]bool) - for _, parameter := range component.Input.Type.Parameters { - paramName := strings.Title(parameter.Name) - value := params.Arguments[paramName] - paramType := parameter.Schema.Type() - if paramType.Kind() == reflect.Ptr { - paramType = paramType.Elem() + uniquePath := map[string]bool{} + uniqueQuery := map[string]bool{} + + // 1) Collect parameters (component + selector pagination) + allParams := r.collectToolParameters(component) + + // 2) Apply parameters to request URL/query/body + for _, p := range allParams { + name := strings.Title(p.Name) + value := params.Arguments[name] + pType := p.Schema.Type() + if pType.Kind() == reflect.Ptr { + pType = pType.Elem() } + value = r.coerceNumericValue(value, pType) + var rpcErr *jsonrpc.Error + baseURL, body, rpcErr = r.applyParamToRequest(baseURL, values, p, value, uniquePath, uniqueQuery, body) + if rpcErr != nil { + return nil, rpcErr + } + } - switch paramType.Kind() { - case reflect.Int, reflect.Int64, reflect.Uint, reflect.Uint64, reflect.Float64: - if value == nil { - continue - } - value = toolbox.AsInt(value) + // 3) Finalize URL with query string + finalURL := baseURL + if enc := values.Encode(); enc != "" { + if strings.Contains(finalURL, "?") { + finalURL += "&" + enc + } else { + finalURL += "?" + enc } + } - switch parameter.In.Kind { - case state.KindPath: - if uniquePath[parameter.In.Name] { - continue - } - uniquePath[parameter.In.Name] = true + // 4) Build HTTP request and route + httpReq, rpcErr := r.newToolHTTPRequest(aRoute.Path.Method, finalURL, body) + if rpcErr != nil { + return nil, rpcErr + } + r.addAuthTokenIfPresent(ctx, httpReq) + httpReq.RequestURI = httpReq.URL.RequestURI() + if uri != aRoute.URI() { + if matched, _ := r.match(component.Method, uri, httpReq); matched != nil { + aRoute = matched + } + } - if value == nil { - return nil, jsonrpc.NewInvalidRequest("missing path parameter: "+parameter.In.Name, nil) - } + rw := proxy.NewWriter() + aRoute.Handle(rw, httpReq) - URL = strings.ReplaceAll(URL, "{"+parameter.In.Name+"}", fmt.Sprintf("%v", value)) - case state.KindQuery, state.KindForm: - if uniqueQuery[parameter.In.Name] { - continue - } - uniqueQuery[parameter.In.Name] = true - if value == nil || value == "" { - continue - } - // Check if value is a slice and create a comma-separated string - if slice, ok := value.([]interface{}); ok { - var items []string - for _, item := range slice { - if f, ok := item.(float64); ok { - items = append(items, fmt.Sprintf("%v", int64(f))) - } else { - items = append(items, fmt.Sprintf("%v", item)) - } - } - values.Add(parameter.In.Name, strings.Join(items, ",")) - } else { - values.Add(parameter.In.Name, fmt.Sprintf("%v", value)) - } - case state.KindRequestBody: - if text, ok := value.(string); ok { - body = strings.NewReader(text) - } else { - data, err := json.Marshal(value) - if err != nil { - return nil, jsonrpc.NewInvalidParamsError("failed to marshal request body: %w", data) - } - body = strings.NewReader(string(data)) - } - } + // 5) Build tool result (text + structured on error) + return r.buildToolCallResult(rw, finalURL, aRoute.Path.Method), nil + } +} + +// collectToolParameters aggregates component input parameters with selector pagination (limit/offset) when available. +func (r *Router) collectToolParameters(component *repository.Component) []*state.Parameter { + var all []*state.Parameter + all = append(all, component.Input.Type.Parameters...) + if component.View != nil && component.View.Selector != nil { + if p := component.View.Selector.LimitParameter; p != nil { + all = append(all, p) + } + if p := component.View.Selector.OffsetParameter; p != nil { + all = append(all, p) + } + if p := component.View.Selector.FieldsParameter; p != nil { + all = append(all, p) } - responseWriter := proxy.NewWriter() + if p := component.View.Selector.PageParameter; p != nil { + all = append(all, p) + } + } + return all +} - // Add query parameters to URL if any exist - if len(values) > 0 { - if strings.Contains(URL, "?") { - URL += "&" + values.Encode() - } else { - URL += "?" + values.Encode() +// coerceNumericValue normalizes numeric values to integers when appropriate. +func (r *Router) coerceNumericValue(value interface{}, paramType reflect.Type) interface{} { + switch paramType.Kind() { + case reflect.Int, reflect.Int64, reflect.Uint, reflect.Uint64, reflect.Float64: + if value == nil { + return nil + } + return toolbox.AsInt(value) + } + return value +} + +// applyParamToRequest applies a single parameter into path placeholders, query/form values, or request body. +func (r *Router) applyParamToRequest(baseURL string, values url.Values, p *state.Parameter, value interface{}, uniquePath, uniqueQuery map[string]bool, body io.Reader) (string, io.Reader, *jsonrpc.Error) { + switch p.In.Kind { + case state.KindPath: + if uniquePath[p.In.Name] { + return baseURL, body, nil + } + uniquePath[p.In.Name] = true + if value == nil { + // If parameter has its own URI segment configured, treat as optional and strip the placeholder. + if p.URI != "" { + baseURL = strings.ReplaceAll(baseURL, "/{"+p.In.Name+"}", "") + baseURL = strings.ReplaceAll(baseURL, "{"+p.In.Name+"}", "") + return baseURL, body, nil } + return baseURL, body, jsonrpc.NewInvalidRequest("missing path parameter: "+p.In.Name, nil) } - httpRequest, err := http.NewRequest(aRoute.Path.Method, URL, body) - if err != nil { - return nil, jsonrpc.NewInvalidRequest(err.Error(), nil) + baseURL = strings.ReplaceAll(baseURL, "{"+p.In.Name+"}", fmt.Sprintf("%v", value)) + case state.KindQuery, state.KindForm: + if uniqueQuery[p.In.Name] { + return baseURL, body, nil + } + uniqueQuery[p.In.Name] = true + if value == nil || value == "" { + return baseURL, body, nil } - r.addAuthTokenIfPresent(ctx, httpRequest) - httpRequest.RequestURI = httpRequest.URL.RequestURI() - if URI != aRoute.URI() { - if matchedRoute, _ := r.match(component.Method, URI, httpRequest); matchedRoute != nil { - aRoute = matchedRoute + if slice, ok := value.([]interface{}); ok { + var items []string + for _, item := range slice { + if f, ok := item.(float64); ok { + items = append(items, fmt.Sprintf("%v", int64(f))) + } else { + items = append(items, fmt.Sprintf("%v", item)) + } } + values.Add(p.In.Name, strings.Join(items, ",")) + } else { + values.Add(p.In.Name, fmt.Sprintf("%v", value)) } - aRoute.Handle(responseWriter, httpRequest) // route the request to the actual handler - var result = schema.CallToolResult{} - mimeType := "application/json" - item := schema.CallToolResultContentElem{ - MimeType: mimeType, - Type: "text", // use data for some clients - Text: responseWriter.Body.String(), + case state.KindRequestBody: + if text, ok := value.(string); ok { + body = strings.NewReader(text) + } else { + data, err := json.Marshal(value) + if err != nil { + return baseURL, body, jsonrpc.NewInvalidParamsError("failed to marshal request body", nil) + } + body = strings.NewReader(string(data)) } - result.Content = append(result.Content, item) - return &result, nil } - return handler + return baseURL, body, nil +} + +// newToolHTTPRequest constructs an HTTP request for routed tool invocation. +func (r *Router) newToolHTTPRequest(method, URL string, body io.Reader) (*http.Request, *jsonrpc.Error) { + httpRequest, err := http.NewRequest(method, URL, body) + if err != nil { + return nil, jsonrpc.NewInvalidRequest(err.Error(), nil) + } + return httpRequest, nil +} + +// buildToolCallResult composes a CallToolResult with text content and structured error info if status is not OK. +func (r *Router) buildToolCallResult(responseWriter *proxy.Writer, URL, method string) *schema.CallToolResult { + var result = &schema.CallToolResult{} + mimeType := responseWriter.HeaderMap.Get("Content-Type") + if mimeType == "" { + mimeType = "application/json" + } + data := responseWriter.Body.Bytes() + result.Content = append(result.Content, schema.CallToolResultContentElem{ + MimeType: mimeType, + Type: "text", + Text: string(data), + }) + _ = json.Unmarshal(data, &result.StructuredContent) + if responseWriter.Code >= http.StatusBadRequest { + isErr := true + result.IsError = &isErr + result.StructuredContent = map[string]interface{}{ + "status": responseWriter.Code, + "error": true, + "message": responseWriter.Body.String(), + "headers": responseWriter.HeaderMap, + "uri": URL, + "method": method, + } + } + return result } func (r *Router) matchToolCallComponentURI(aRoute *Route, component *repository.Component, params schema.CallToolRequestParams) string { @@ -190,6 +270,7 @@ func (r *Router) buildToolInputType(components *repository.Component) reflect.Ty var inputFields []reflect.StructField var uniqueQuery = make(map[string]bool) var uniquePath = make(map[string]bool) + // Include component input parameters for _, parameter := range components.Input.Type.Parameters { name := strings.Title(parameter.Name) switch parameter.In.Kind { @@ -198,20 +279,63 @@ func (r *Router) buildToolInputType(components *repository.Component) reflect.Ty continue } uniquePath[parameter.In.Name] = true - inputFields = append(inputFields, reflect.StructField{Name: name, Type: parameter.Schema.Type()}) + // If parameter is a slice, make it optional in schema via `omitempty` and optional:"true". + var tag reflect.StructTag + if parameter.Schema != nil && parameter.Schema.Type().Kind() == reflect.Slice { + tag = `json:",omitempty" optional:"true"` + } + inputFields = append(inputFields, reflect.StructField{Name: name, Type: parameter.Schema.Type(), Tag: tag}) case state.KindQuery, state.KindForm: if uniqueQuery[parameter.In.Name] { continue } uniqueQuery[parameter.In.Name] = true + // Repeated (slice) params are optional regardless of "required" tag. + // Otherwise, respect explicit required; default to optional. tag := reflect.StructTag(parameter.Tag) - if !strings.Contains(parameter.Tag, "required") { + if parameter.Schema != nil && parameter.Schema.Type().Kind() == reflect.Slice { + tag = `json:",omitempty" optional:"true"` + } else if !strings.Contains(parameter.Tag, "required") { tag = `json:",omitempty"` } inputFields = append(inputFields, reflect.StructField{Name: name, Type: parameter.Schema.Type(), Tag: tag}) case state.KindRequestBody: - inputFields = append(inputFields, reflect.StructField{Name: name, Type: parameter.Schema.Type()}) + // If body is a slice, mark optional in schema. + var tag reflect.StructTag + if parameter.Schema != nil && parameter.Schema.Type().Kind() == reflect.Slice { + tag = `json:",omitempty" optional:"true"` + } + inputFields = append(inputFields, reflect.StructField{Name: name, Type: parameter.Schema.Type(), Tag: tag}) + } + } + + // Include selector (limit/offset/fields/page) for read components when available + if components.View != nil && components.View.Selector != nil { + if p := components.View.Selector.LimitParameter; p != nil && p.In != nil && p.In.Name != "" { + if !uniqueQuery[p.In.Name] { // avoid duplicates + uniqueQuery[p.In.Name] = true + inputFields = append(inputFields, reflect.StructField{Name: strings.Title(p.Name), Type: p.Schema.Type(), Tag: `json:",omitempty"`}) + } + } + if p := components.View.Selector.OffsetParameter; p != nil && p.In != nil && p.In.Name != "" { + if !uniqueQuery[p.In.Name] { + uniqueQuery[p.In.Name] = true + inputFields = append(inputFields, reflect.StructField{Name: strings.Title(p.Name), Type: p.Schema.Type(), Tag: `json:",omitempty"`}) + } + } + if p := components.View.Selector.FieldsParameter; p != nil && p.In != nil && p.In.Name != "" { + if !uniqueQuery[p.In.Name] { + uniqueQuery[p.In.Name] = true + // Fields is a []string – ensure optional in schema + inputFields = append(inputFields, reflect.StructField{Name: strings.Title(p.Name), Type: p.Schema.Type(), Tag: `json:",omitempty" optional:"true"`}) + } + } + if p := components.View.Selector.PageParameter; p != nil && p.In != nil && p.In.Name != "" { + if !uniqueQuery[p.In.Name] { + uniqueQuery[p.In.Name] = true + inputFields = append(inputFields, reflect.StructField{Name: strings.Title(p.Name), Type: p.Schema.Type(), Tag: `json:",omitempty"`}) + } } } @@ -229,6 +353,23 @@ func (r *Router) buildTemplateResourceIntegration(item *dpath.Item, aPath *dpath parameterNames = append(parameterNames, parameter.In.Name) } } + // Also expose view selector pagination controls in URI template if present + if provider != nil { + if comp, err := provider.Component(context.Background()); err == nil && comp.View != nil && comp.View.Selector != nil { + if p := comp.View.Selector.LimitParameter; p != nil && p.In != nil && p.In.Name != "" { + parameterNames = append(parameterNames, p.In.Name) + } + if p := comp.View.Selector.OffsetParameter; p != nil && p.In != nil && p.In.Name != "" { + parameterNames = append(parameterNames, p.In.Name) + } + if p := comp.View.Selector.FieldsParameter; p != nil && p.In != nil && p.In.Name != "" { + parameterNames = append(parameterNames, p.In.Name) + } + if p := comp.View.Selector.PageParameter; p != nil && p.In != nil && p.In.Name != "" { + parameterNames = append(parameterNames, p.In.Name) + } + } + } canBuildTemplateResource := len(parameterNames) > 0 || strings.Contains(aPath.URI, "{") if !canBuildTemplateResource { return nil diff --git a/gateway/router/marshal/json/marshaller_map.go b/gateway/router/marshal/json/marshaller_map.go index 320001bbe..427868bf1 100644 --- a/gateway/router/marshal/json/marshaller_map.go +++ b/gateway/router/marshal/json/marshaller_map.go @@ -203,6 +203,9 @@ func (m *mapMarshaller) mapStringIfaceMarshaller() func(pointer unsafe.Pointer, return nil } + // Ensure JSON special characters in keys are escaped + replacer := getReplacer() + if !m.isEmbedded { sb.WriteString("{") } @@ -214,9 +217,9 @@ func (m *mapMarshaller) mapStringIfaceMarshaller() func(pointer unsafe.Pointer, sb.WriteString(",") } counter++ - sb.WriteString(`"`) - sb.WriteString(namesIndex.formatTo(aKey, m.config.CaseFormat)) - sb.WriteString(`":`) + // Write escaped key + marshallString(namesIndex.formatTo(aKey, m.config.CaseFormat), sb, replacer) + sb.WriteString(`:`) if err := m.valueMarshaller.MarshallObject(AsPtr(aValue, m.valueType), sb); err != nil { return err diff --git a/gateway/router/marshal/json/marshaller_strings.go b/gateway/router/marshal/json/marshaller_strings.go index c044fc5b6..f19f91325 100644 --- a/gateway/router/marshal/json/marshaller_strings.go +++ b/gateway/router/marshal/json/marshaller_strings.go @@ -49,9 +49,54 @@ func (i *stringMarshaller) ensureReplacer() { } } -func marshallString(asString string, sb *MarshallSession, replacer *strings.Replacer) { +func marshallString(asString string, sb *MarshallSession, _ *strings.Replacer) { + // Fully JSON-escape the string, including control chars and JS line/paragraph separators. + const hexDigits = "0123456789abcdef" sb.WriteByte('"') - sb.WriteString(replacer.Replace(asString)) + for i := 0; i < len(asString); i++ { + c := asString[i] + switch c { + case '\\', '"': + sb.WriteByte('\\') + sb.WriteByte(c) + case '/': + sb.WriteByte('\\') + sb.WriteByte('/') + case '\b': + sb.WriteString(`\\b`) + case '\f': + sb.WriteString(`\\f`) + case '\n': + sb.WriteString(`\\n`) + case '\r': + sb.WriteString(`\\r`) + case '\t': + sb.WriteString(`\\t`) + default: + // Escape other control characters < 0x20 as \u00XX + if c < 0x20 { + sb.WriteString(`\\u00`) + sb.WriteByte(hexDigits[c>>4]) + sb.WriteByte(hexDigits[c&0x0F]) + continue + } + // Escape U+2028 and U+2029 to be safe for JS embed contexts + if c == 0xE2 && i+2 < len(asString) { + c1 := asString[i+1] + c2 := asString[i+2] + if c1 == 0x80 && (c2 == 0xA8 || c2 == 0xA9) { + if c2 == 0xA8 { + sb.WriteString(`\\u2028`) + } else { + sb.WriteString(`\\u2029`) + } + i += 2 + continue + } + } + sb.WriteByte(c) + } + } sb.WriteByte('"') } diff --git a/go.mod b/go.mod index 7af2f0c20..5ff45f3ab 100644 --- a/go.mod +++ b/go.mod @@ -48,9 +48,9 @@ require ( require ( github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d github.com/viant/firebase v0.1.1 - github.com/viant/jsonrpc v0.9.0 + github.com/viant/jsonrpc v0.11.0 github.com/viant/mcp v0.6.0 - github.com/viant/mcp-protocol v0.5.7 + github.com/viant/mcp-protocol v0.5.10 github.com/viant/structology v0.6.1 github.com/viant/tagly v0.2.2 github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa @@ -166,3 +166,4 @@ require ( modernc.org/token v1.0.0 // indirect ) +replace github.com/viant/mcp => ../mcp diff --git a/go.sum b/go.sum index 3912edbdf..2f063153d 100644 --- a/go.sum +++ b/go.sum @@ -1124,12 +1124,10 @@ github.com/viant/govalidator v0.3.1 h1:V7f/KgfzbP8fVDc+Kj+jyPvfXxMr2N1x7srOlDV6l github.com/viant/govalidator v0.3.1/go.mod h1:D35Dwx0R8rR1knRxhlseoYvOkiqo24kpMg1/o977i9Y= github.com/viant/igo v0.2.0 h1:ygWmTCinnGPaeV7omJLiyneOpzYZ5kiw7oYz7mUJZVQ= github.com/viant/igo v0.2.0/go.mod h1:7V6AWsLhKWeGzXNTNH3AZiIEKa0m33DrQbdWtapsI74= -github.com/viant/jsonrpc v0.9.0 h1:vTZsApJxTd3Y50ygOBs8HKCJ24NrwgCa7lqG1oYXpdE= -github.com/viant/jsonrpc v0.9.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= -github.com/viant/mcp v0.6.0 h1:+BCsLSW5pux07avEhS550hZno8Y5ZKKSfdLm6NHRU+8= -github.com/viant/mcp v0.6.0/go.mod h1:fb5wpE9kc/R32pNE4Pdo1DR4ZW6+0em3rsFuBHoqmp4= -github.com/viant/mcp-protocol v0.5.7 h1:3ifypMAy+oUjQEAsq+XwrAhE/B/3eIes4yXdhoRF9Eo= -github.com/viant/mcp-protocol v0.5.7/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= +github.com/viant/jsonrpc v0.11.0 h1:SqOztRwLWTCdK+VSU0XhZvwqeHrJ1hpQcmhPY6NXH5g= +github.com/viant/jsonrpc v0.11.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= +github.com/viant/mcp-protocol v0.5.10 h1:915EC1GKgBbyYF4efzRSZ/AE6f4vobkbwa2qe6OOjJ0= +github.com/viant/mcp-protocol v0.5.10/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b/go.mod h1:85fneXJbErKMGhSQto3A5ElTQCwl3t74U9cSV0waBHw= github.com/viant/pgo v0.11.0 h1:PNuYVhwTfyrAHGBO6lxaMFuHP4NkjKV8ULecz3OWk8c= diff --git a/repository/component.go b/repository/component.go index 5a22bdee6..ec106e47a 100644 --- a/repository/component.go +++ b/repository/component.go @@ -170,6 +170,109 @@ func (c *Component) initView(ctx context.Context, resource *view.Resource) error if err := c.View.Init(ctx, resource); err != nil { return err } + // For read components (GET), expose and enable offset/limit/fields/page/orderBy for each namespaced view. + if strings.EqualFold(c.Path.Method, http.MethodGet) { + // Helper to enable limit/offset for a view with namespace prefix (if any) + ensureSelectors := func(v *view.View, nsPrefix string) { + if v == nil { + return + } + if v.Selector == nil { + v.Selector = &view.Config{} + } + if v.Selector.Constraints == nil { + v.Selector.Constraints = &view.Constraints{} + } + // Enable constraints + v.Selector.Constraints.Limit = true + v.Selector.Constraints.Offset = true + v.Selector.Constraints.Projection = true + v.Selector.Constraints.OrderBy = true + + // Limit param + if v.Selector.LimitParameter == nil { + p := *view.QueryStateParameters.LimitParameter + p.Description = view.Description(view.LimitQuery, v.Name) + if nsPrefix != "" { + p.In = state.NewQueryLocation(nsPrefix + view.LimitQuery) + } + v.Selector.LimitParameter = &p + } else if v.Selector.LimitParameter.Description == "" { + v.Selector.LimitParameter.Description = view.Description(view.LimitQuery, v.Name) + } + + // Offset param + if v.Selector.OffsetParameter == nil { + p := *view.QueryStateParameters.OffsetParameter + p.Description = view.Description(view.OffsetQuery, v.Name) + if nsPrefix != "" { + p.In = state.NewQueryLocation(nsPrefix + view.OffsetQuery) + } + v.Selector.OffsetParameter = &p + } else if v.Selector.OffsetParameter.Description == "" { + v.Selector.OffsetParameter.Description = view.Description(view.OffsetQuery, v.Name) + } + + // Fields param (controls which fields are included) + if v.Selector.FieldsParameter == nil { + p := *view.QueryStateParameters.FieldsParameter + p.Description = view.Description(view.FieldsQuery, v.Name) + if nsPrefix != "" { + p.In = state.NewQueryLocation(nsPrefix + view.FieldsQuery) + } + v.Selector.FieldsParameter = &p + } else if v.Selector.FieldsParameter.Description == "" { + v.Selector.FieldsParameter.Description = view.Description(view.FieldsQuery, v.Name) + } + + // Page param (paging interface on top of limit/offset) + if v.Selector.PageParameter == nil { + p := *view.QueryStateParameters.PageParameter + p.Description = view.Description(view.PageQuery, v.Name) + if nsPrefix != "" { + p.In = state.NewQueryLocation(nsPrefix + view.PageQuery) + } + v.Selector.PageParameter = &p + } else if v.Selector.PageParameter.Description == "" { + v.Selector.PageParameter.Description = view.Description(view.PageQuery, v.Name) + } + + // OrderBy param + if v.Selector.OrderByParameter == nil { + p := *view.QueryStateParameters.OrderByParameter + p.Description = view.Description(view.OrderByQuery, v.Name) + if nsPrefix != "" { + p.In = state.NewQueryLocation(nsPrefix + view.OrderByQuery) + } + v.Selector.OrderByParameter = &p + } else if v.Selector.OrderByParameter.Description == "" { + v.Selector.OrderByParameter.Description = view.Description(view.OrderByQuery, v.Name) + } + } + + // Root view + nsPrefix := "" + if c.View.Selector != nil && c.View.Selector.Namespace != "" { + nsPrefix = c.View.Selector.Namespace + } + ensureSelectors(c.View, nsPrefix) + + // All related views via NamespacedView + if c.NamespacedView != nil { + for _, nsView := range c.NamespacedView.Views { + v := nsView.View + // Determine ns prefix from NamespacedView (prefer non-empty namespace if present) + pfx := "" + for _, ns := range nsView.Namespaces { + if ns != "" { + pfx = ns + break + } + } + ensureSelectors(v, pfx) + } + } + } holder := "" if c.Contract.Output.Type.Parameters != nil { if rootHolder := c.Contract.Output.Type.Parameters.LookupByLocation(state.KindOutput, "view"); rootHolder != nil { From 520d4c353ba673f0711feb3a02e148d8a2c9b1e5 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 20 Oct 2025 09:17:50 -0700 Subject: [PATCH 050/117] enhanced mcp integration --- go.mod | 1 - 1 file changed, 1 deletion(-) diff --git a/go.mod b/go.mod index 5ff45f3ab..b9bf9e443 100644 --- a/go.mod +++ b/go.mod @@ -166,4 +166,3 @@ require ( modernc.org/token v1.0.0 // indirect ) -replace github.com/viant/mcp => ../mcp From fce13f39c3a08cda87761f4bd45886175dbc2890 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 20 Oct 2025 09:19:02 -0700 Subject: [PATCH 051/117] enhanced mcp integration --- go.mod | 3 +-- go.sum | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index b9bf9e443..43b7b8438 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d github.com/viant/firebase v0.1.1 github.com/viant/jsonrpc v0.11.0 - github.com/viant/mcp v0.6.0 + github.com/viant/mcp v0.7.0 github.com/viant/mcp-protocol v0.5.10 github.com/viant/structology v0.6.1 github.com/viant/tagly v0.2.2 @@ -165,4 +165,3 @@ require ( modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.0 // indirect ) - diff --git a/go.sum b/go.sum index 2f063153d..20c6ae58a 100644 --- a/go.sum +++ b/go.sum @@ -1126,6 +1126,8 @@ github.com/viant/igo v0.2.0 h1:ygWmTCinnGPaeV7omJLiyneOpzYZ5kiw7oYz7mUJZVQ= github.com/viant/igo v0.2.0/go.mod h1:7V6AWsLhKWeGzXNTNH3AZiIEKa0m33DrQbdWtapsI74= github.com/viant/jsonrpc v0.11.0 h1:SqOztRwLWTCdK+VSU0XhZvwqeHrJ1hpQcmhPY6NXH5g= github.com/viant/jsonrpc v0.11.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= +github.com/viant/mcp v0.7.0 h1:pIsT93/45pDxpphsZgS8d+0mIzNDihZH0zCDADxGqe8= +github.com/viant/mcp v0.7.0/go.mod h1:4Kk48IEvnAwkplg9sLs1lOBY3cRdsYjrn4lXXdPOPMo= github.com/viant/mcp-protocol v0.5.10 h1:915EC1GKgBbyYF4efzRSZ/AE6f4vobkbwa2qe6OOjJ0= github.com/viant/mcp-protocol v0.5.10/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28= From 120a696c2fa04a4794b0565e2f518f1dc3a37b05 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 20 Oct 2025 13:25:22 -0700 Subject: [PATCH 052/117] enhanced mcp integration --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 43b7b8438..eaa512277 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d github.com/viant/firebase v0.1.1 github.com/viant/jsonrpc v0.11.0 - github.com/viant/mcp v0.7.0 + github.com/viant/mcp v0.7.2 github.com/viant/mcp-protocol v0.5.10 github.com/viant/structology v0.6.1 github.com/viant/tagly v0.2.2 diff --git a/go.sum b/go.sum index 20c6ae58a..318e88f4e 100644 --- a/go.sum +++ b/go.sum @@ -1128,6 +1128,8 @@ github.com/viant/jsonrpc v0.11.0 h1:SqOztRwLWTCdK+VSU0XhZvwqeHrJ1hpQcmhPY6NXH5g= github.com/viant/jsonrpc v0.11.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= github.com/viant/mcp v0.7.0 h1:pIsT93/45pDxpphsZgS8d+0mIzNDihZH0zCDADxGqe8= github.com/viant/mcp v0.7.0/go.mod h1:4Kk48IEvnAwkplg9sLs1lOBY3cRdsYjrn4lXXdPOPMo= +github.com/viant/mcp v0.7.2 h1:+vkzxFIlKWsjTY/56oBcHuPBlO+9lNb1cwwm2FXA/cA= +github.com/viant/mcp v0.7.2/go.mod h1:4Kk48IEvnAwkplg9sLs1lOBY3cRdsYjrn4lXXdPOPMo= github.com/viant/mcp-protocol v0.5.10 h1:915EC1GKgBbyYF4efzRSZ/AE6f4vobkbwa2qe6OOjJ0= github.com/viant/mcp-protocol v0.5.10/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28= From bcb769bc1726954f0b61b89ceb2df7d3aa747cf0 Mon Sep 17 00:00:00 2001 From: adranwit Date: Sun, 26 Oct 2025 20:51:37 -0700 Subject: [PATCH 053/117] enhanced mcp integration --- go.mod | 4 ++-- go.sum | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index eaa512277..1ec14f461 100644 --- a/go.mod +++ b/go.mod @@ -48,8 +48,8 @@ require ( require ( github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d github.com/viant/firebase v0.1.1 - github.com/viant/jsonrpc v0.11.0 - github.com/viant/mcp v0.7.2 + github.com/viant/jsonrpc v0.15.0 + github.com/viant/mcp v0.8.0 github.com/viant/mcp-protocol v0.5.10 github.com/viant/structology v0.6.1 github.com/viant/tagly v0.2.2 diff --git a/go.sum b/go.sum index 318e88f4e..d80772bcb 100644 --- a/go.sum +++ b/go.sum @@ -1126,10 +1126,18 @@ github.com/viant/igo v0.2.0 h1:ygWmTCinnGPaeV7omJLiyneOpzYZ5kiw7oYz7mUJZVQ= github.com/viant/igo v0.2.0/go.mod h1:7V6AWsLhKWeGzXNTNH3AZiIEKa0m33DrQbdWtapsI74= github.com/viant/jsonrpc v0.11.0 h1:SqOztRwLWTCdK+VSU0XhZvwqeHrJ1hpQcmhPY6NXH5g= github.com/viant/jsonrpc v0.11.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= +github.com/viant/jsonrpc v0.14.0 h1:YppPzIidbd9bgjKHCREXkvjkJXf8AaFGGWfk1r+nCJE= +github.com/viant/jsonrpc v0.14.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= +github.com/viant/jsonrpc v0.15.0 h1:0qy9vzgNwR9Gj1C+ouSrzNUtNDzKGogO+7TZR+cFrA4= +github.com/viant/jsonrpc v0.15.0/go.mod h1:b214Lo4zBwLqbu6Tf2bRlgQkFfPMBW5ap4qS+I3zcJ8= github.com/viant/mcp v0.7.0 h1:pIsT93/45pDxpphsZgS8d+0mIzNDihZH0zCDADxGqe8= github.com/viant/mcp v0.7.0/go.mod h1:4Kk48IEvnAwkplg9sLs1lOBY3cRdsYjrn4lXXdPOPMo= github.com/viant/mcp v0.7.2 h1:+vkzxFIlKWsjTY/56oBcHuPBlO+9lNb1cwwm2FXA/cA= github.com/viant/mcp v0.7.2/go.mod h1:4Kk48IEvnAwkplg9sLs1lOBY3cRdsYjrn4lXXdPOPMo= +github.com/viant/mcp v0.7.5 h1:8Gmdz4LiZ1Ot8eUaLCufqWtivrkGGjBA1ra41cdmgmo= +github.com/viant/mcp v0.7.5/go.mod h1:3eBNG5U/CCOPbLdBpF3clwS11WfxEYB6MdzTL2s4jLo= +github.com/viant/mcp v0.8.0 h1:n4tnLXpOtpnrLZtHyNG2mmZ9SUbGWKsWGla10iMfuDg= +github.com/viant/mcp v0.8.0/go.mod h1:fyuB1TSQYbbGNn7U6rLmlr9gD+Yg5+Na32D34Uvm0sk= github.com/viant/mcp-protocol v0.5.10 h1:915EC1GKgBbyYF4efzRSZ/AE6f4vobkbwa2qe6OOjJ0= github.com/viant/mcp-protocol v0.5.10/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28= From d847cf1fd63a7689b040cebd3b92e372a3939987 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 27 Oct 2025 05:51:57 -0700 Subject: [PATCH 054/117] patched parser --- internal/translator/parser/statement.go | 43 ++++++++++++++----------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/internal/translator/parser/statement.go b/internal/translator/parser/statement.go index 3874f4c48..39633964f 100644 --- a/internal/translator/parser/statement.go +++ b/internal/translator/parser/statement.go @@ -38,42 +38,49 @@ func (s Statements) DMLTables(rawSQL string) []string { var tables = make(map[string]bool) var result []string for _, statement := range s { + // Only consider exec statements for DML table extraction. + if !statement.IsExec { + continue + } SQL := rawSQL[statement.Start:statement.End] - usesService := strings.Contains(SQL, "$sql.") - lowerCasedDML := strings.ToLower(SQL) - quoted := "" - - if index := strings.Index(SQL, `"`); index != -1 { - quoted = SQL[index+1:] - if index = strings.Index(quoted, `"`); index != -1 { - quoted = quoted[:index] + // Handle service-based exec ($sql.Insert/$sql.Update) only when explicitly detected as service. + if statement.Kind == shared.ExecKindService { + quoted := "" + if index := strings.Index(SQL, `"`); index != -1 { + quoted = SQL[index+1:] + if index = strings.Index(quoted, `"`); index != -1 { + quoted = quoted[:index] + } } - } - if usesService && quoted != "" { - statement.Table = quoted - if _, ok := tables[statement.Table]; ok { + if quoted != "" { + statement.Table = quoted + if _, ok := tables[statement.Table]; ok { + continue + } + result = append(result, statement.Table) + tables[statement.Table] = true continue } - result = append(result, statement.Table) - tables[statement.Table] = true - continue } + + lowerCasedDML := strings.ToLower(SQL) + if strings.Contains(lowerCasedDML, "insert") { - if stmt, _ := sqlparser.ParseInsert(SQL); stmt != nil { + if stmt, _ := sqlparser.ParseInsert(SQL); stmt != nil && stmt.Target.X != nil { if table := sqlparser.Stringify(stmt.Target.X); table != "" { statement.Table = table } } } else if strings.Contains(lowerCasedDML, "update") { - if stmt, _ := sqlparser.ParseUpdate(SQL); stmt != nil { + if stmt, _ := sqlparser.ParseUpdate(SQL); stmt != nil && stmt.Target.X != nil { if table := sqlparser.Stringify(stmt.Target.X); table != "" { statement.Table = table } } } else if strings.Contains(lowerCasedDML, "delete") { - if stmt, _ := sqlparser.ParseDelete(SQL); stmt != nil { + if stmt, _ := sqlparser.ParseDelete(SQL); stmt != nil && stmt.Target.X != nil { if table := sqlparser.Stringify(stmt.Target.X); table != "" { statement.Table = table } From d06c78404fd4a425fb64441832ced78b727b121b Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 28 Oct 2025 12:20:49 -0700 Subject: [PATCH 055/117] patched parser --- service/operator/reader.go | 2 +- service/operator/service.go | 15 ++++++++++----- view/state/hook.go | 10 +++++++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/service/operator/reader.go b/service/operator/reader.go index e882d0643..1e1ae41f4 100644 --- a/service/operator/reader.go +++ b/service/operator/reader.go @@ -44,7 +44,7 @@ func (s *Service) runQuery(ctx context.Context, component *repository.Component, if err := s.updateJobStatusDone(ctx, component, handlerResponse, setting.SyncFlag, startTime); err != nil { return nil, err } - if output, err = s.finalize(ctx, handlerResponse.Output, handlerResponse.Error); err != nil { + if output, err = s.finalize(ctx, handlerResponse.Output, handlerResponse.Error, nil); err != nil { aSession.ClearCache(component.Output.Type.Parameters) return s.HandleError(ctx, aSession, component, err) } diff --git a/service/operator/service.go b/service/operator/service.go index bf50ece0b..960105e6a 100644 --- a/service/operator/service.go +++ b/service/operator/service.go @@ -6,6 +6,10 @@ import ( "encoding/json" "errors" "fmt" + "net/http" + "reflect" + "time" + "github.com/viant/afs" "github.com/viant/afs/file" "github.com/viant/datly/repository" @@ -29,9 +33,6 @@ import ( "github.com/viant/xdatly/handler/response" hstate "github.com/viant/xdatly/handler/state" "google.golang.org/api/googleapi" - "net/http" - "reflect" - "time" ) type Service struct { @@ -118,13 +119,17 @@ func (s *Service) operate(ctx context.Context, aComponent *repository.Component, } } - return s.finalize(ctx, ret, err) + return s.finalize(ctx, ret, err, aSession) } return nil, response.NewError(500, fmt.Sprintf("unsupported Type %v", aComponent.Service)) } -func (s *Service) finalize(ctx context.Context, ret interface{}, err error) (interface{}, error) { +func (s *Service) finalize(ctx context.Context, ret interface{}, err error, aSession *session.Session) (interface{}, error) { + if injectorFinalizer, ok := ret.(state.InjectorFinalizer); ok { + err = injectorFinalizer.Finalize(ctx, aSession) + return ret, err + } if err != nil { return ret, err } diff --git a/view/state/hook.go b/view/state/hook.go index 9ae5b49c4..a4125cb44 100644 --- a/view/state/hook.go +++ b/view/state/hook.go @@ -1,6 +1,10 @@ package state -import "context" +import ( + "context" + + "github.com/viant/xdatly/handler/state" +) // Initializer is an interface that should be implemented by any type that needs to be initialized type Initializer interface { @@ -11,3 +15,7 @@ type Initializer interface { type Finalizer interface { Finalize(ctx context.Context) error } + +type InjectorFinalizer interface { + Finalize(ctx context.Context, injector state.Injector) error +} From b88cbd582b0a962218a01ec5556298480256b8c5 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 28 Oct 2025 12:40:49 -0700 Subject: [PATCH 056/117] patched parser --- view/state/types.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/view/state/types.go b/view/state/types.go index 292ad4147..f301290ea 100644 --- a/view/state/types.go +++ b/view/state/types.go @@ -11,6 +11,9 @@ type Types struct { } func (c *Types) Lookup(p reflect.Type) (*Type, bool) { + if len(c.types) == 0 { + return nil, false + } c.RWMutex.RLock() ret, ok := c.types[p] c.RWMutex.RUnlock() From 1b5e79ff29bc13859ab3aacea5d408f487e62505 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 28 Oct 2025 12:47:53 -0700 Subject: [PATCH 057/117] patched parser --- service/operator/reader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/operator/reader.go b/service/operator/reader.go index 1e1ae41f4..801638e12 100644 --- a/service/operator/reader.go +++ b/service/operator/reader.go @@ -44,7 +44,7 @@ func (s *Service) runQuery(ctx context.Context, component *repository.Component, if err := s.updateJobStatusDone(ctx, component, handlerResponse, setting.SyncFlag, startTime); err != nil { return nil, err } - if output, err = s.finalize(ctx, handlerResponse.Output, handlerResponse.Error, nil); err != nil { + if output, err = s.finalize(ctx, handlerResponse.Output, handlerResponse.Error, aSession); err != nil { aSession.ClearCache(component.Output.Type.Parameters) return s.HandleError(ctx, aSession, component, err) } From c26fd5e5fd7edf5a275ce1dcfd882882ced651f8 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 28 Oct 2025 13:13:44 -0700 Subject: [PATCH 058/117] patched parser --- service/operator/service.go | 15 ++++++++++++++- service/session/state.go | 8 ++++++++ view/state/hook.go | 3 ++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/service/operator/service.go b/service/operator/service.go index 960105e6a..a5a61ecb1 100644 --- a/service/operator/service.go +++ b/service/operator/service.go @@ -15,6 +15,7 @@ import ( "github.com/viant/datly/repository" rasync "github.com/viant/datly/repository/async" "github.com/viant/datly/repository/content" + "github.com/viant/datly/repository/contract" "github.com/viant/datly/service" "github.com/viant/datly/service/reader" "github.com/viant/datly/service/session" @@ -29,9 +30,11 @@ import ( xhandler "github.com/viant/xdatly/handler" "github.com/viant/xdatly/handler/async" "github.com/viant/xdatly/handler/exec" + xhttp "github.com/viant/xdatly/handler/http" "github.com/viant/xdatly/handler/logger" "github.com/viant/xdatly/handler/response" hstate "github.com/viant/xdatly/handler/state" + xstate "github.com/viant/xdatly/handler/state" "google.golang.org/api/googleapi" ) @@ -85,6 +88,7 @@ func (s *Service) HandleError(ctx context.Context, aSession *session.Session, aC func (s *Service) operate(ctx context.Context, aComponent *repository.Component, aSession *session.Session) (interface{}, error) { var err error + ctx, err = s.EnsureContext(ctx, aSession, aComponent) if err != nil { return nil, err @@ -127,7 +131,16 @@ func (s *Service) operate(ctx context.Context, aComponent *repository.Component, func (s *Service) finalize(ctx context.Context, ret interface{}, err error, aSession *session.Session) (interface{}, error) { if injectorFinalizer, ok := ret.(state.InjectorFinalizer); ok { - err = injectorFinalizer.Finalize(ctx, aSession) + + lookup := func(ctx context.Context, route xhttp.Route) (xstate.Injector, error) { + aComponent, err := aSession.Registry().Lookup(ctx, contract.NewPath(route.Method, route.URL)) + if err != nil { + return nil, err + } + return aSession.NewSession(aComponent), nil + } + + err = injectorFinalizer.Finalize(ctx, lookup) return ret, err } if err != nil { diff --git a/service/session/state.go b/service/session/state.go index 8e6eab3f3..63904496e 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" "github.com/viant/datly/internal/converter" + "github.com/viant/datly/repository" "github.com/viant/datly/service/auth" "github.com/viant/datly/utils/types" "github.com/viant/datly/view" @@ -42,6 +43,13 @@ type ( } ) +func (s *Session) NewSession(component *repository.Component) *Session { + ret := *s + s.component = component + s.view = component.View + return &ret +} + func (s *Session) SetView(view *view.View) { s.view = view } diff --git a/view/state/hook.go b/view/state/hook.go index a4125cb44..e871f4d6d 100644 --- a/view/state/hook.go +++ b/view/state/hook.go @@ -3,6 +3,7 @@ package state import ( "context" + "github.com/viant/xdatly/handler/http" "github.com/viant/xdatly/handler/state" ) @@ -17,5 +18,5 @@ type Finalizer interface { } type InjectorFinalizer interface { - Finalize(ctx context.Context, injector state.Injector) error + Finalize(ctx context.Context, getInjector func(ctx context.Context, path http.Route) (state.Injector, error)) error } From 57d9ca6a83439d62fbe672b690be8b0e82ae9936 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 28 Oct 2025 13:45:22 -0700 Subject: [PATCH 059/117] patched parser --- service/session/state.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/session/state.go b/service/session/state.go index 63904496e..68fef2ae7 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -45,8 +45,8 @@ type ( func (s *Session) NewSession(component *repository.Component) *Session { ret := *s - s.component = component - s.view = component.View + ret.component = component + ret.view = component.View return &ret } From 452af4fa118ac00a3503b6616d2d53e305364b67 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 28 Oct 2025 14:02:27 -0700 Subject: [PATCH 060/117] patched parser --- service/session/state.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service/session/state.go b/service/session/state.go index 68fef2ae7..005425dfc 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -45,8 +45,9 @@ type ( func (s *Session) NewSession(component *repository.Component) *Session { ret := *s - ret.component = component - ret.view = component.View + s.component = component + s.locatorOpt.Views.Register(component.View) + s.view = component.View return &ret } From 82d6bb5c6914c61486a9cbbd8bc9b272476e1aff Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 29 Oct 2025 07:58:29 -0700 Subject: [PATCH 061/117] patched parser --- service/executor/handler/executor.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/service/executor/handler/executor.go b/service/executor/handler/executor.go index ce20877d0..3e21d27f1 100644 --- a/service/executor/handler/executor.go +++ b/service/executor/handler/executor.go @@ -173,6 +173,7 @@ func (e *Executor) newSqlService(options *sqlx.Options) (sqlx.Sqlx, error) { } func (e *Executor) getDataUnit(options *sqlx.Options) (*expand.DataUnit, error) { + e.ensureConnectors() if (options.WithDb == nil && options.WithTx == nil) && options.WithConnector == e.view.Connector.Name { return e.dataUnit, nil } @@ -197,6 +198,11 @@ func (e *Executor) getDataUnit(options *sqlx.Options) (*expand.DataUnit, error) if connector == nil { return nil, fmt.Errorf("failed to lookup connector %v", options.WithConnector) } + + if _, ok := e.connectors[options.WithConnector]; !ok { + e.connectors[options.WithConnector] = connector + } + db, err := connector.DB() if err != nil { return nil, err @@ -211,6 +217,17 @@ func (e *Executor) getDataUnit(options *sqlx.Options) (*expand.DataUnit, error) return e.dataUnit, nil } +func (e *Executor) ensureConnectors() { + if len(e.connectors) == 0 { + e.connectors = make(view.Connectors) + if res := e.view.GetResource(); res != nil { + for _, connector := range res.Connectors { + e.connectors[connector.Name] = connector + } + } + } +} + func (e *Executor) Execute(ctx context.Context) error { if e.executed { return nil @@ -222,6 +239,10 @@ func (e *Executor) Execute(ctx context.Context) error { dbOptions = append(dbOptions, executor.WithTx(e.tx)) } + err := service.ExecuteStmts(ctx, executor.NewViewDBSource(e.view), newSqlxIterator(e.dataUnit.Statements.Executable), dbOptions...) + if err != nil { + return err + } for _, unit := range e.dataUnits { dbSource := &DbSource{} dbSource.db, _ = unit.MetaSource.Db() @@ -230,7 +251,7 @@ func (e *Executor) Execute(ctx context.Context) error { } } - return service.ExecuteStmts(ctx, executor.NewViewDBSource(e.view), newSqlxIterator(e.dataUnit.Statements.Executable), dbOptions...) + return err } func (e *Executor) ExpandAndExecute(ctx context.Context) (*executor.Session, error) { From d002e57dc294d5598b81b450398b82f87a60c972 Mon Sep 17 00:00:00 2001 From: arao Date: Thu, 30 Oct 2025 15:32:20 -0700 Subject: [PATCH 062/117] ENG-00000 structql update --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index fa54285be..df198a925 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/viant/pgo v0.11.0 github.com/viant/scy v0.24.0 github.com/viant/sqlx v0.17.8 - github.com/viant/structql v0.5.2 + github.com/viant/structql v0.5.3 github.com/viant/toolbox v0.37.0 github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 github.com/viant/xreflect v0.7.3 diff --git a/go.sum b/go.sum index 3914ffdf7..a3e9e8c48 100644 --- a/go.sum +++ b/go.sum @@ -1138,14 +1138,12 @@ github.com/viant/scy v0.24.0 h1:KAC3IUARkQxTNSuwBK2YhVBJMOOLN30YaLKHbbuSkMU= github.com/viant/scy v0.24.0/go.mod h1:7uNRS67X45YN+JqTLCcMEhehffVjqrejULEDln9p0Ao= github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns= github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= -github.com/viant/sqlx v0.17.7 h1:drUv3N8mOboq917gnmcT9zC4G9vj4jU11bO/SsLpmc8= -github.com/viant/sqlx v0.17.7/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/sqlx v0.17.8 h1:YxGTrXC2B1JmDz1qp8G+G9hGPk7XCRevWN1E4E+ZlCI= github.com/viant/sqlx v0.17.8/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= github.com/viant/structology v0.6.1/go.mod h1:63XfkzUyNw7wdi99HJIsH2Rg3d5AOumqbWLUYytOkxU= -github.com/viant/structql v0.5.2 h1:0dAratszxC6AD/TNaV8BnLQQprNO5GJHaKjmszrIoeY= -github.com/viant/structql v0.5.2/go.mod h1:nm9AYnAuSKH7b7pG+dKVxbQrr1Mgp1CQEMvUwwkE+I8= +github.com/viant/structql v0.5.3 h1:QeOxvF0so8VFGt5bm+Jr6FL8uRnXkvwWY+ZCkbe3zsI= +github.com/viant/structql v0.5.3/go.mod h1:nm9AYnAuSKH7b7pG+dKVxbQrr1Mgp1CQEMvUwwkE+I8= github.com/viant/tagly v0.2.2 h1:qqb4Dov83i7nl7Gewph/lLaYAF8MKv0N7y34scgRNmE= github.com/viant/tagly v0.2.2/go.mod h1:vV8QgJkhug+X+qyKds8av0fhjD+4u7IhNtowL1KGQ5A= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= From 37994e2c3cb56071a7689b3fd1b23aead6982581 Mon Sep 17 00:00:00 2001 From: arao Date: Fri, 31 Oct 2025 10:35:34 -0700 Subject: [PATCH 063/117] ENG-0000 datly tarslate for Patch --- internal/translator/resource.go | 8 +++++--- internal/translator/service.go | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/translator/resource.go b/internal/translator/resource.go index 163684277..db7e97121 100644 --- a/internal/translator/resource.go +++ b/internal/translator/resource.go @@ -474,9 +474,11 @@ func (r *Resource) expandSQL(viewlet *Viewlet) (*sqlx.SQL, error) { func (r *Resource) ensureViewParametersSchema(ctx context.Context, setType func(ctx context.Context, setType *Viewlet) error) error { viewParameters := r.State.FilterByKind(state.KindView) for _, viewParameter := range viewParameters { - if viewParameter.Schema != nil && viewParameter.Schema.Type() != nil { - continue - } + //WE DO NOT NEEDED IT + //if viewParameter.Schema != nil && viewParameter.Schema.Type() != nil { + // fmt.Printf("skipping view %v %v\n", viewParameter.Name, viewParameter.Schema) + // //continue + //} if viewParameter.In.Name == "" { //default root schema continue } diff --git a/internal/translator/service.go b/internal/translator/service.go index 6f7cbcbc2..539ceade9 100644 --- a/internal/translator/service.go +++ b/internal/translator/service.go @@ -577,7 +577,8 @@ func (s *Service) buildQueryViewletType(ctx context.Context, viewlet *Viewlet) e func (s *Service) buildViewletType(ctx context.Context, db *sql.DB, viewlet *Viewlet) (err error) { shared.EnsureArgs(viewlet.Expanded.Query, &viewlet.Expanded.Args) - if viewlet.Spec, err = inference.NewSpec(ctx, db, &s.Repository.Messages, viewlet.Table.Name, viewlet.ColumnConfig, viewlet.Expanded.Query, viewlet.Expanded.Args...); err != nil { + viewlet.Spec, err = inference.NewSpec(ctx, db, &s.Repository.Messages, viewlet.Table.Name, viewlet.ColumnConfig, viewlet.Expanded.Query, viewlet.Expanded.Args...) + if err != nil { return fmt.Errorf("failed to create spec for %v, %w", viewlet.Name, err) } From 6437e5db561d4a29442d020cba080778257a24fc Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 31 Oct 2025 14:20:40 -0700 Subject: [PATCH 064/117] patched parser --- service/session/option.go | 8 ++++++++ service/session/state.go | 34 +++++++++++++++++++++++++++++++--- service/session/stater.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/service/session/option.go b/service/session/option.go index 148242cb4..099835813 100644 --- a/service/session/option.go +++ b/service/session/option.go @@ -33,6 +33,7 @@ type ( scope string embeddedFS *embed.FS auth *auth.Service + preseedCache bool } Option func(o *Options) @@ -155,6 +156,13 @@ func WithAuth(auth *auth.Service) Option { } } +// WithPreseedCache controls whether NewSession should pre-seed child cache from parent (default false) +func WithPreseedCache(flag bool) Option { + return func(s *Options) { + s.preseedCache = flag + } +} + func WithComponent(component *repository.Component) Option { return func(s *Options) { s.component = component diff --git a/service/session/state.go b/service/session/state.go index 005425dfc..3f28d36b5 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -45,9 +45,37 @@ type ( func (s *Session) NewSession(component *repository.Component) *Session { ret := *s - s.component = component - s.locatorOpt.Views.Register(component.View) - s.view = component.View + // set component and view on the child session (do not mutate receiver) + ret.component = component + ret.Options.component = component + ret.view = component.View + if ret.locatorOpt != nil { + if _, ok := ret.locatorOpt.Views[component.View.Name]; !ok { + ret.locatorOpt.Views.Register(component.View) + } + } + + // create a fresh cache and optionally pre-populate from parent cache values + parent := s.cache + ret.cache = newCache() + if ret.Options.preseedCache && parent != nil { + parent.RWMutex.RLock() + for k, v := range parent.values { + ret.cache.values[k] = v + } + parent.RWMutex.RUnlock() + } + + // reset predicates (filters) on the child session state + if ret.Options.state != nil { + ret.Options.state.RWMutex.Lock() + for _, st := range ret.Options.state.Views { + if st != nil { + st.Filters = nil + } + } + ret.Options.state.RWMutex.Unlock() + } return &ret } diff --git a/service/session/stater.go b/service/session/stater.go index a98548014..abda758bd 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -92,6 +92,40 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt } hOptions := hstate.NewOptions(opts...) + + // Handle WithInput: preload cache from provided input data + if input := hOptions.Input(); input != nil { + var parameters state.Parameters + // If input type matches component input type, reuse component parameters + if s.component != nil && s.component.Input.Type.Type() != nil && s.component.Input.Type.Type().Type() != nil { + compInType := s.component.Input.Type.Type().Type() + inType := reflect.TypeOf(input) + if inType != nil && inType.Kind() != reflect.Ptr { + inType = reflect.PtrTo(inType) + } + if inType == compInType { + parameters = s.component.Input.Type.Parameters + } + } + // Otherwise, derive parameters from input type + if len(parameters) == 0 { + inType := reflect.TypeOf(input) + aType, e := state.NewType( + state.WithSchema(state.NewSchema(inType)), + state.WithResource(s.resource), + ) + if e != nil { + return e + } + if e = aType.Init(); e != nil { + return e + } + parameters = aType.Parameters + } + if e := s.LoadState(parameters, input); e != nil { + return e + } + } aState := stateType.Type().WithValue(dest) var stateOptions = []locator.Option{ locator.WithLogger(s.logger), From 8bb9c6a124074712514c79927e64a7fea024a980 Mon Sep 17 00:00:00 2001 From: adranwit Date: Sat, 1 Nov 2025 09:54:17 -0700 Subject: [PATCH 065/117] patched parser --- service/executor/expand/evaluator.go | 3 +-- service/session/stater.go | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/service/executor/expand/evaluator.go b/service/executor/expand/evaluator.go index f898b4ffa..c733aca79 100644 --- a/service/executor/expand/evaluator.go +++ b/service/executor/expand/evaluator.go @@ -4,8 +4,6 @@ import ( "context" "errors" "fmt" - "reflect" - "github.com/viant/datly/view/keywords" "github.com/viant/datly/view/state/predicate" "github.com/viant/godiff" @@ -14,6 +12,7 @@ import ( "github.com/viant/velty/est" "github.com/viant/velty/est/op" "github.com/viant/xreflect" + "reflect" ) type ( diff --git a/service/session/stater.go b/service/session/stater.go index abda758bd..c87a6966f 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -10,6 +10,7 @@ import ( "embed" "github.com/viant/datly/utils/types" + "github.com/viant/datly/view" "github.com/viant/datly/view/state" "github.com/viant/datly/view/state/kind/locator" "github.com/viant/xdatly/handler/response" @@ -125,6 +126,9 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt if e := s.LoadState(parameters, input); e != nil { return e } + if s.view.Mode == view.ModeQuery { + s.SetViewState(ctx, s.view) + } } aState := stateType.Type().WithValue(dest) var stateOptions = []locator.Option{ From 14be98fdeb238b8389cc995f934aa48da725762a Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 5 Nov 2025 05:08:10 -0800 Subject: [PATCH 066/117] added tx option and added support for multi part --- go.mod | 2 +- go.sum | 4 + service/executor/handler/executor.go | 18 +++++ service/session/option.go | 14 ++++ view/extension/init.go | 3 +- view/state/kind/locator/body.go | 116 ++++++++++++++++++++++++--- 6 files changed, 145 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 60a5356a0..6ae51f459 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( github.com/viant/tagly v0.2.2 github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 - github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa + github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a github.com/viant/xlsy v0.3.1 diff --git a/go.sum b/go.sum index b5a5dd475..f427f0da7 100644 --- a/go.sum +++ b/go.sum @@ -1170,6 +1170,10 @@ github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 h1:9Yry3PUB github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259/go.mod h1:fb8YgbVadk8X5ZLz49LWGzWmQlZd7Y/I5wE0ru44bIo= github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa h1:UzX1wB23RMENSKF5X0fQZR/cIy7wB7z2ODWCIm358IQ= github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= +github.com/viant/xdatly/handler v0.0.0-20251101181445-c75586bb6ea4 h1:qlYPNwGIfejalMBSoLFhpgNk0LZMRFL6NRfQnpetjPc= +github.com/viant/xdatly/handler v0.0.0-20251101181445-c75586bb6ea4/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= +github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e h1:WJb6NjQP/84Fqovpesy6TqST2ukHLFF+lTI9Vz43O5I= +github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 h1:G+e1MMDxQXUPPlAXVNlRqSLTLra7udGQZUu3hnr0Y8M= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52/go.mod h1:LJN2m8xJjtYNCvyvNrVanJwvzj8+hYCuPswL8H4qRG0= github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a h1:jecH7mH63gj1zJwD18SdvSHM9Ttr9FEOnhHkYfkCNkI= diff --git a/service/executor/handler/executor.go b/service/executor/handler/executor.go index 3e21d27f1..70f1746ba 100644 --- a/service/executor/handler/executor.go +++ b/service/executor/handler/executor.go @@ -95,6 +95,12 @@ func (e *Executor) Session(ctx context.Context) (*executor.Session, error) { e.executorSession = sess sess.SessionHandler = sessionHandler + // inherit tx from session options if available + if e.tx == nil { + if tx := e.session.Options.SqlTx(); tx != nil { + e.tx = tx + } + } return e.executorSession, err } @@ -162,6 +168,10 @@ func (e *Executor) newSqlService(options *sqlx.Options) (sqlx.Sqlx, error) { if unit == e.dataUnit { //we are using View that can contain SQL Statements in Velty txStartedNotifier = e.txStarted } + // default SQLx tx to executor tx to avoid internal Begin/Commit if caller provided one + if options.WithTx == nil && e.tx != nil { + options.WithTx = e.tx + } return &Service{ txNotifier: txStartedNotifier, dataUnit: unit, @@ -314,6 +324,10 @@ func (e *Executor) redirect(ctx context.Context, route *http2.Route, opts ...hst session.WithLogger(e.logger), session.WithRegistry(registry), ) + if tx := stateOptions.SqlTx(); tx != nil { + // associate tx with session; child executor will reuse it + aSession.Apply(session.WithSQLTx(tx)) + } err = aSession.InitKinds(state.KindComponent, state.KindHeader, state.KindRequestBody, state.KindForm, state.KindQuery) if err != nil { @@ -321,6 +335,10 @@ func (e *Executor) redirect(ctx context.Context, route *http2.Route, opts ...hst } ctx = aSession.Context(ctx, true) anExecutor := NewExecutor(aComponent.View, aSession) + // ensure Execute(ctx) uses the provided tx (avoid autocommit) + if tx := stateOptions.SqlTx(); tx != nil { + anExecutor.tx = tx + } return anExecutor.NewHandlerSession(ctx, WithLogger(aSession.Logger())) } diff --git a/service/session/option.go b/service/session/option.go index 099835813..3568b7b35 100644 --- a/service/session/option.go +++ b/service/session/option.go @@ -2,6 +2,7 @@ package session import ( "context" + "database/sql" "embed" "github.com/viant/datly/repository" @@ -34,6 +35,7 @@ type ( embeddedFS *embed.FS auth *auth.Service preseedCache bool + sqlTx *sql.Tx } Option func(o *Options) @@ -47,6 +49,11 @@ func (o *Options) Registry() *repository.Registry { return o.registry } +// SqlTx returns associated SQL transaction (if any) +func (o *Options) SqlTx() *sql.Tx { + return o.sqlTx +} + func (o *Options) HasInputParameters() bool { if o.locatorOpt == nil { return false @@ -156,6 +163,13 @@ func WithAuth(auth *auth.Service) Option { } } +// WithSQLTx associates an existing SQL transaction with the session +func WithSQLTx(tx *sql.Tx) Option { + return func(s *Options) { + s.sqlTx = tx + } +} + // WithPreseedCache controls whether NewSession should pre-seed child cache from parent (default false) func WithPreseedCache(flag bool) Option { return func(s *Options) { diff --git a/view/extension/init.go b/view/extension/init.go index f05ff7140..a4cd462cd 100644 --- a/view/extension/init.go +++ b/view/extension/init.go @@ -3,6 +3,7 @@ package extension import ( "encoding/json" "fmt" + "mime/multipart" "net/http" dcodec "github.com/viant/datly/view/extension/codec" @@ -52,7 +53,7 @@ func InitRegistry() { xreflect.NewType("validator.Violation", xreflect.WithReflectType(reflect.TypeOf(validator.Violation{}))), xreflect.NewType("RawMessage", xreflect.WithReflectType(reflect.TypeOf(json.RawMessage{}))), xreflect.NewType("json.RawMessage", xreflect.WithReflectType(reflect.TypeOf(json.RawMessage{}))), - xreflect.NewType("json.RawMessage", xreflect.WithReflectType(reflect.TypeOf(json.RawMessage{}))), + xreflect.NewType("multipart.FileHeader", xreflect.WithReflectType(reflect.TypeOf(multipart.FileHeader{}))), xreflect.NewType("types.BitBool", xreflect.WithReflectType(reflect.TypeOf(types.BitBool(true)))), xreflect.NewType("time.Time", xreflect.WithReflectType(xreflect.TimeType)), xreflect.NewType("response.Status", xreflect.WithReflectType(reflect.TypeOf(response.Status{}))), diff --git a/view/state/kind/locator/body.go b/view/state/kind/locator/body.go index b80d112dd..aeb5ab428 100644 --- a/view/state/kind/locator/body.go +++ b/view/state/kind/locator/body.go @@ -3,13 +3,17 @@ package locator import ( "context" "fmt" + "mime" + "mime/multipart" + "net/http" + "reflect" + "strings" + "sync" + "github.com/viant/datly/shared" "github.com/viant/datly/view/state/kind" "github.com/viant/structology" hstate "github.com/viant/xdatly/handler/state" - "net/http" - "reflect" - "sync" ) type Body struct { @@ -21,24 +25,26 @@ type Body struct { request *http.Request err error sync.Once + isMultipart bool } +const maxMultipartMemory = 32 << 20 // 32 MiB + func (r *Body) Names() []string { return nil } func (r *Body) Value(ctx context.Context, rType reflect.Type, name string) (interface{}, bool, error) { var err error - - r.Once.Do(func() { - var request *http.Request - request, r.err = shared.CloneHTTPRequest(r.request) - r.body, r.err = readRequestBody(request) - - }) + r.initOnce() var requestState *structology.State + // Multipart handling + if r.isMultipart { + return r.handleMultipartValue(rType, name) + } + if len(r.body) > 0 { if r.requestState != nil && r.requestState.Type().Type() == rType { requestState = r.requestState @@ -75,6 +81,67 @@ func (r *Body) Value(ctx context.Context, rType reflect.Type, name string) (inte return sel.Value(requestState.Pointer()), true, nil } +// initOnce initializes body locator state based on content type (multipart vs non-multipart) +func (r *Body) initOnce() { + r.Once.Do(func() { + // Multipart branch + if r.request != nil && r.isMultipartRequest() { + r.isMultipart = true + r.err = r.request.ParseMultipartForm(maxMultipartMemory) + if r.err == nil { + r.seedFormFromMultipart() + } + return + } + // Non-multipart: clone and read body safely + var request *http.Request + request, r.err = shared.CloneHTTPRequest(r.request) + r.body, r.err = readRequestBody(request) + }) +} + +// handleMultipartValue returns value for multipart/form-data content +func (r *Body) handleMultipartValue(rType reflect.Type, name string) (interface{}, bool, error) { + if r.err != nil { + return nil, false, r.err + } + if r.request == nil || r.request.MultipartForm == nil { + return nil, false, nil + } + if name == "" { + return nil, false, nil + } + // File destinations + if rType != nil { + // []*multipart.FileHeader + if rType.Kind() == reflect.Slice && rType.Elem() == reflect.TypeOf((*multipart.FileHeader)(nil)) { + files := r.request.MultipartForm.File[name] + if len(files) == 0 { + return nil, false, nil + } + return files, true, nil + } + // *multipart.FileHeader + if rType == reflect.TypeOf((*multipart.FileHeader)(nil)) { + files := r.request.MultipartForm.File[name] + if len(files) == 0 { + return nil, false, nil + } + return files[0], true, nil + } + } + // Textual parts + if r.request.MultipartForm.Value != nil { + if vs, ok := r.request.MultipartForm.Value[name]; ok && len(vs) > 0 { + if rType != nil && rType.Kind() == reflect.Slice && rType.Elem().Kind() == reflect.String { + return vs, true, nil + } + return vs[0], true, nil + } + } + return nil, false, nil +} + func (r *Body) decodeBodyMap(ctx context.Context) (interface{}, bool, error) { aMapPtr := reflect.New(r.bodyType) aMap := reflect.MakeMap(r.bodyType) @@ -152,3 +219,32 @@ func (r *Body) updateQueryString(ctx context.Context, body interface{}) { // Encode the query string and assign it back to the request's URL req.URL.RawQuery = q.Encode() } + +// isMultipartRequest checks content type for multipart/form-data +func (r *Body) isMultipartRequest() bool { + if r.request == nil { + return false + } + ct := r.request.Header.Get("Content-Type") + if ct == "" { + return false + } + mediaType, _, err := mime.ParseMediaType(ct) + if err != nil { + return strings.Contains(strings.ToLower(ct), "multipart/form-data") + } + return strings.EqualFold(mediaType, "multipart/form-data") +} + +// seedFormFromMultipart copies textual multipart values into shared form to avoid re-parsing later +func (r *Body) seedFormFromMultipart() { + if r.request == nil || r.request.MultipartForm == nil || r.form == nil { + return + } + for k, vs := range r.request.MultipartForm.Value { + if len(vs) == 0 { + continue + } + r.form.Set(k, vs...) + } +} From 5811a0a6ae4644cd79695a850411e166c73583c9 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 5 Nov 2025 05:10:41 -0800 Subject: [PATCH 067/117] added tx option and added support for multi part --- shared/http.go | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/shared/http.go b/shared/http.go index 5b84f39f5..3504c2546 100644 --- a/shared/http.go +++ b/shared/http.go @@ -3,22 +3,35 @@ package shared import ( "bytes" "io" + "mime" "net/http" + "strings" ) // CloneHTTPRequest clones http request func CloneHTTPRequest(request *http.Request) (*http.Request, error) { - var data []byte - var err error + // Shallow clone; special-case multipart to avoid buffering entire body ret := *request ret.URL = request.URL - if request.Body != nil { - if data, err = readRequestBody(request); err != nil { - return nil, err - } - ret.Body = io.NopCloser(bytes.NewReader(data)) + + if request.Body == nil { + return &ret, nil + } + + // Detect multipart/form-data; avoid reading/consuming body + if isMultipartRequest(request) { + // share the same Body; caller must ensure only one reader consumes it + ret.Body = request.Body + return &ret, nil + } + + // Non-multipart: safe full read, reset both original and clone bodies + data, err := readRequestBody(request) + if err != nil { + return nil, err } - return &ret, err + ret.Body = io.NopCloser(bytes.NewReader(data)) + return &ret, nil } func readRequestBody(request *http.Request) ([]byte, error) { @@ -30,3 +43,18 @@ func readRequestBody(request *http.Request) ([]byte, error) { request.Body = io.NopCloser(bytes.NewReader(data)) return data, err } + +func isMultipartRequest(r *http.Request) bool { + if r == nil || r.Header == nil { + return false + } + ct := r.Header.Get("Content-Type") + if ct == "" { + return false + } + mediaType, _, err := mime.ParseMediaType(ct) + if err != nil { + return strings.Contains(strings.ToLower(ct), "multipart/form-data") + } + return strings.EqualFold(mediaType, "multipart/form-data") +} From d7ce972f738300b65388841d68a41f3567d095e8 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 5 Nov 2025 18:20:31 -0800 Subject: [PATCH 068/117] added tx option and added support for multi part --- gateway/route.go | 43 ++++- .../marshal/json/marshaller_bool_ptr.go | 2 +- .../marshal/json/marshaller_raw_message.go | 13 +- .../marshal/json/marshaller_struct_test.go | 169 ++++++++++++++++++ 4 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 gateway/router/marshal/json/marshaller_struct_test.go diff --git a/gateway/route.go b/gateway/route.go index 4bec8528a..0c15f9bdb 100644 --- a/gateway/route.go +++ b/gateway/route.go @@ -13,6 +13,9 @@ import ( "github.com/viant/xdatly/handler/exec" "net/http" "strings" + "time" + + dlogger "github.com/viant/datly/logger" ) const ( @@ -33,6 +36,9 @@ type ( Handler func(ctx context.Context, response http.ResponseWriter, req *http.Request) `json:"-"` logging.Config Version string + + // Counter is an optional per-route metrics counter + Counter dlogger.Counter `json:"-"` } ) @@ -43,7 +49,39 @@ func (r *Route) Handle(res http.ResponseWriter, req *http.Request) int { ctx := context.Background() execContext := exec.NewContext(req.Method, req.RequestURI, req.Header, r.Version) ctx = vcontext.WithValue(ctx, exec.ContextKey, execContext) + var onDone func(time.Time, ...interface{}) int64 = nil + var start time.Time + if r.Counter != nil { + start = time.Now() + onDone = r.Counter.Begin(start) + } + r.Handler(ctx, res, req) + + // finalize metrics + if onDone != nil { + end := time.Now() + onDone(end) + // Determine final status code + statusCode := execContext.StatusCode + if statusCode == 0 { + statusCode = http.StatusOK + } + // Increment error/success buckets + if statusCode >= 200 && statusCode < 300 { + r.Counter.IncrementValue("Success") + r.Counter.IncrementValue("status:2xx") + } else if statusCode >= 400 && statusCode < 500 { + r.Counter.IncrementValue("Error") + r.Counter.IncrementValue("status:4xx") + } else if statusCode >= 500 { + r.Counter.IncrementValue("Error") + r.Counter.IncrementValue("status:5xx") + } else { + // Treat other codes as success by default + r.Counter.IncrementValue("Success") + } + } if execContext.StatusCode == 0 { execContext.StatusCode = http.StatusOK } @@ -66,7 +104,7 @@ func (r *Router) NewRouteHandler(handler *router.Handler) *Route { if !strings.HasPrefix(URI, "/") { URI = "/" + URI } - return &Route{ + route := &Route{ Path: &handler.Path.Path, MCP: &handler.Path.ModelContextProtocol, Meta: &handler.Path.Meta, @@ -75,6 +113,9 @@ func (r *Router) NewRouteHandler(handler *router.Handler) *Route { Config: r.config.Logging, Version: r.config.Version, } + // Pre-register and attach per-route counter if metrics are enabled + route.Counter = r.ensureRouteCounter(context.Background(), handler.Provider) + return route } func (r *Route) URI() string { diff --git a/gateway/router/marshal/json/marshaller_bool_ptr.go b/gateway/router/marshal/json/marshaller_bool_ptr.go index 86a562a9d..9a54f47f6 100644 --- a/gateway/router/marshal/json/marshaller_bool_ptr.go +++ b/gateway/router/marshal/json/marshaller_bool_ptr.go @@ -35,5 +35,5 @@ func (i *boolPtrMarshaller) MarshallObject(ptr unsafe.Pointer, sb *MarshallSessi } func (i *boolPtrMarshaller) UnmarshallObject(pointer unsafe.Pointer, decoder *gojay.Decoder, auxiliaryDecoder *gojay.Decoder, session *UnmarshalSession) error { - return decoder.AddBool(xunsafe.AsBoolPtr(pointer)) + return decoder.AddBoolNull(xunsafe.AsBoolAddrPtr(pointer)) } diff --git a/gateway/router/marshal/json/marshaller_raw_message.go b/gateway/router/marshal/json/marshaller_raw_message.go index 5ed57e11f..75686d0c2 100644 --- a/gateway/router/marshal/json/marshaller_raw_message.go +++ b/gateway/router/marshal/json/marshaller_raw_message.go @@ -1,6 +1,7 @@ package json import ( + stdjson "encoding/json" "github.com/francoispqt/gojay" "github.com/viant/xunsafe" "unsafe" @@ -14,12 +15,16 @@ func newRawMessageMarshaller() *rawMessageMarshaller { func (r *rawMessageMarshaller) UnmarshallObject(pointer unsafe.Pointer, decoder *gojay.Decoder, auxiliaryDecoder *gojay.Decoder, session *UnmarshalSession) error { bytesPtr := xunsafe.AsBytesPtr(pointer) - dst := "" - if err := decoder.DecodeString(&dst); err != nil { + // Decode arbitrary JSON value into interface{}, then re-marshal to raw bytes. + var val interface{} + if err := decoder.AddInterface(&val); err != nil { return err } - - *bytesPtr = []byte(dst) + data, err := stdjson.Marshal(val) + if err != nil { + return err + } + *bytesPtr = data return nil } diff --git a/gateway/router/marshal/json/marshaller_struct_test.go b/gateway/router/marshal/json/marshaller_struct_test.go new file mode 100644 index 000000000..845b1e433 --- /dev/null +++ b/gateway/router/marshal/json/marshaller_struct_test.go @@ -0,0 +1,169 @@ +package json + +import ( + stdjson "encoding/json" + "reflect" + "testing" + "time" + + "github.com/viant/datly/gateway/router/marshal/config" + "github.com/viant/tagly/format/text" +) + +// Session represents a user session document. +type Session struct { + // UserID is the PK of the session set. + UserID int `aerospike:"user_id,pk"` + // LastSeen is the last activity timestamp. Stored as unix seconds. + LastSeen *time.Time `aerospike:"last_seen,unixsec"` + // Disabled marks the session as inactive. + Disabled *bool `aerospike:"disabled"` + // Attribute holds session attributes entries. + Attribute []Attribute +} + +// Attribute represents a single attribute entry stored within the session's attributes map bin. +// The PK is still `user_id`, and attribute entries are keyed by `name`. +type Attribute struct { + // UserID is the session owner and record key. + UserID int `aerospike:"user_id,pk"` + // Name is the attribute key (map key). + Name *string `aerospike:"name,mapKey"` + // Value is the attribute payload; supports native Aerospike types. + Value stdjson.RawMessage `aerospike:"value"` +} + +func newMarshaller() *Marshaller { + // We force lowerCamel JSON keys and a time layout that matches the sample payload offset (e.g. "-08"). + cfg := &config.IOConfig{ + CaseFormat: text.CaseFormatLowerCamel, + TimeLayout: "2006-01-02T15:04:05-07", + } + return New(cfg) +} + +func TestUnmarshal_SessionWithAttributes(t *testing.T) { + payload := `[{"attribute":[{"name":"theme","userId":252,"value":{"color":"dark"}}],"disabled":false,"lastSeen":"2025-11-05T17:00:07-08","userId":252}]` + + var got []Session + err := newMarshaller().Unmarshal([]byte(payload), &got) + if err != nil { + t.Fatalf("unexpected unmarshal error: %v", err) + } + if len(got) != 1 { + t.Fatalf("expected 1 session, got %d", len(got)) + } + + s := got[0] + if s.UserID != 252 { + t.Fatalf("expected userId=252, got %d", s.UserID) + } + if s.Disabled == nil || *s.Disabled != false { + t.Fatalf("expected disabled=false, got %v", s.Disabled) + } + if s.LastSeen == nil { + t.Fatalf("expected lastSeen to be set") + } + // Verify attributes + if len(s.Attribute) != 1 { + t.Fatalf("expected 1 attribute, got %d", len(s.Attribute)) + } + a := s.Attribute[0] + if a.UserID != 252 { + t.Fatalf("expected attribute.userId=252, got %d", a.UserID) + } + if a.Name == nil || *a.Name != "theme" { + if a.Name == nil { + t.Fatalf("expected attribute.name=theme, got ") + } + t.Fatalf("expected attribute.name=theme, got %s", *a.Name) + } + // Ensure raw value round-trips as expected JSON + var valueObj map[string]string + if err := stdjson.Unmarshal(a.Value, &valueObj); err != nil { + t.Fatalf("unexpected attribute.value unmarshal error: %v", err) + } + expected := map[string]string{"color": "dark"} + if !reflect.DeepEqual(valueObj, expected) { + t.Fatalf("unexpected attribute.value: got %+v want %+v", valueObj, expected) + } +} + +func TestMarshal_SessionWithAttributes(t *testing.T) { + name := "theme" + disabled := false + ts, err := time.Parse("2006-01-02T15:04:05-07", "2025-11-05T17:00:07-08") + if err != nil { + t.Fatalf("invalid test time: %v", err) + } + raw := stdjson.RawMessage(`{"color":"dark"}`) + data := []Session{ + { + UserID: 252, + LastSeen: &ts, + Disabled: &disabled, + Attribute: []Attribute{ + {UserID: 252, Name: &name, Value: raw}, + }, + }, + } + + out, err := newMarshaller().Marshal(data) + if err != nil { + t.Fatalf("unexpected marshal error: %v", err) + } + + // Compare semantically by decoding both expected and actual into generic values. + expected := `[{"attribute":[{"name":"theme","userId":252,"value":{"color":"dark"}}],"disabled":false,"lastSeen":"2025-11-05T17:00:07-08","userId":252}]` + + var gotVal, wantVal interface{} + if err := stdjson.Unmarshal(out, &gotVal); err != nil { + t.Fatalf("unexpected result json: %v, body=%s", err, string(out)) + } + if err := stdjson.Unmarshal([]byte(expected), &wantVal); err != nil { + t.Fatalf("invalid expected json: %v", err) + } + if !reflect.DeepEqual(gotVal, wantVal) { + t.Fatalf("mismatch json:\n got: %s\nwant: %s", string(out), expected) + } +} + +func TestBoolPointer_NullAndPresent(t *testing.T) { + // Case 1: disabled is null -> Disabled == nil + payloadNull := `[{"userId":1,"disabled":null}]` + var s1 []Session + if err := newMarshaller().Unmarshal([]byte(payloadNull), &s1); err != nil { + t.Fatalf("unmarshal null disabled: %v", err) + } + if len(s1) != 1 || s1[0].Disabled != nil { + t.Fatalf("expected Disabled=nil, got %+v", s1) + } + + // Case 2: disabled false -> Disabled != nil and false + payloadFalse := `[{"userId":1,"disabled":false}]` + var s2 []Session + if err := newMarshaller().Unmarshal([]byte(payloadFalse), &s2); err != nil { + t.Fatalf("unmarshal false disabled: %v", err) + } + if len(s2) != 1 || s2[0].Disabled == nil || *s2[0].Disabled != false { + t.Fatalf("expected Disabled=false pointer, got %+v", s2) + } + + // Case 3: marshal with Disabled=nil -> emits null + data := []Session{{UserID: 3}} + out, err := newMarshaller().Marshal(data) + if err != nil { + t.Fatalf("marshal nil disabled: %v", err) + } + // verify null present for disabled if not omitted by config + var v []map[string]interface{} + if err := stdjson.Unmarshal(out, &v); err != nil { + t.Fatalf("decode marshalled: %v", err) + } + if _, ok := v[0]["disabled"]; !ok { + t.Fatalf("expected disabled key present; got %s", string(out)) + } + if v[0]["disabled"] != nil { + t.Fatalf("expected disabled=null, got %v", v[0]["disabled"]) + } +} From c15bb61d7c608e7895eb3162c864ceb8fd8300af Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 6 Nov 2025 05:23:33 -0800 Subject: [PATCH 069/117] added tx option and added support for multi part --- gateway/route_metrics.go | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 gateway/route_metrics.go diff --git a/gateway/route_metrics.go b/gateway/route_metrics.go new file mode 100644 index 000000000..213f6c4a3 --- /dev/null +++ b/gateway/route_metrics.go @@ -0,0 +1,73 @@ +package gateway + +import ( + "context" + "path" + "strings" + "time" + + dlogger "github.com/viant/datly/logger" + "github.com/viant/datly/repository" + gprovider "github.com/viant/gmetric/provider" +) + +// ensureRouteCounter pre-registers a per-route counter and returns a logger-compatible adapter. +func (r *Router) ensureRouteCounter(ctx context.Context, prov *repository.Provider) dlogger.Counter { + if r.metrics == nil || prov == nil { + return nil + } + component, err := prov.Component(ctx) + if err != nil || component == nil || component.View == nil { + return nil + } + + v := component.View + + // Derive a stable package from resource URL similar to view.discoverPackage + pkg := "datly" + if res := v.GetResource(); res != nil { + src := res.SourceURL + // Extract the dir and find the segment after "/routes/" + parent, _ := path.Split(src) + if idx := strings.Index(parent, "/routes/"); idx != -1 { + pkg = strings.Trim(parent[idx+len("/routes/"):], "/") + } + } + + // Build a metric operation name aligned with view metrics namespace, but scoped to component URI (.request) + method := component.Path.Method + normURI := normalizeURI(component.URI) + name := strings.Trim(normURI, "/") + ".request" + name = strings.ReplaceAll(name, "/", ".") + metricName := pkg + "." + name + if method != "" && !strings.EqualFold(method, "GET") { + metricName = method + ":" + metricName + } + metricName = strings.ReplaceAll(metricName, "/", ".") + + cnt := r.metrics.LookupOperation(metricName) + if cnt == nil { + // Title: human-friendly + title := v.Name + " request" + cnt = r.metrics.MultiOperationCounter(pkg, metricName, title, time.Millisecond, time.Minute, 2, gprovider.NewBasic()) + } + return dlogger.NewCounter(cnt) +} + +// normalizeURI replaces path parameters like {id} with a constant token to limit cardinality. +func normalizeURI(uri string) string { + res := uri + for { + i := strings.Index(res, "{") + if i == -1 { + break + } + j := strings.Index(res[i:], "}") + if j == -1 { + break + } + j = i + j + 1 + res = res[:i] + "T" + res[j:] + } + return res +} From 9ef102c0b34bea2f79c6e96a2e552c7d293e918c Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 6 Nov 2025 11:55:13 -0800 Subject: [PATCH 070/117] patched multi content upload --- gateway/route.go | 8 ++++---- view/extension/init.go | 1 + view/state/kind/locator/body.go | 22 ++++++++++++++++++---- view/state/kind/locator/http.go | 3 ++- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/gateway/route.go b/gateway/route.go index 0c15f9bdb..9f5cf6eed 100644 --- a/gateway/route.go +++ b/gateway/route.go @@ -3,6 +3,10 @@ package gateway import ( "context" "encoding/json" + "net/http" + "strings" + "time" + "github.com/viant/afs/url" "github.com/viant/datly/gateway/router" "github.com/viant/datly/repository" @@ -11,9 +15,6 @@ import ( "github.com/viant/datly/repository/path" vcontext "github.com/viant/datly/view/context" "github.com/viant/xdatly/handler/exec" - "net/http" - "strings" - "time" dlogger "github.com/viant/datly/logger" ) @@ -55,7 +56,6 @@ func (r *Route) Handle(res http.ResponseWriter, req *http.Request) int { start = time.Now() onDone = r.Counter.Begin(start) } - r.Handler(ctx, res, req) // finalize metrics diff --git a/view/extension/init.go b/view/extension/init.go index a4cd462cd..ea5ff3730 100644 --- a/view/extension/init.go +++ b/view/extension/init.go @@ -53,6 +53,7 @@ func InitRegistry() { xreflect.NewType("validator.Violation", xreflect.WithReflectType(reflect.TypeOf(validator.Violation{}))), xreflect.NewType("RawMessage", xreflect.WithReflectType(reflect.TypeOf(json.RawMessage{}))), xreflect.NewType("json.RawMessage", xreflect.WithReflectType(reflect.TypeOf(json.RawMessage{}))), + xreflect.NewType("FileHeader", xreflect.WithReflectType(reflect.TypeOf(multipart.FileHeader{}))), xreflect.NewType("multipart.FileHeader", xreflect.WithReflectType(reflect.TypeOf(multipart.FileHeader{}))), xreflect.NewType("types.BitBool", xreflect.WithReflectType(reflect.TypeOf(types.BitBool(true)))), xreflect.NewType("time.Time", xreflect.WithReflectType(xreflect.TimeType)), diff --git a/view/state/kind/locator/body.go b/view/state/kind/locator/body.go index aeb5ab428..d0c6c2150 100644 --- a/view/state/kind/locator/body.go +++ b/view/state/kind/locator/body.go @@ -37,7 +37,6 @@ func (r *Body) Names() []string { func (r *Body) Value(ctx context.Context, rType reflect.Type, name string) (interface{}, bool, error) { var err error r.initOnce() - var requestState *structology.State // Multipart handling @@ -157,15 +156,30 @@ func (r *Body) decodeBodyMap(ctx context.Context) (interface{}, bool, error) { // NewBody returns body locator func NewBody(opts ...Option) (kind.Locator, error) { options := NewOptions(opts) - if options.BodyType == nil { - return nil, fmt.Errorf("body type was empty") - } if options.request == nil { return nil, fmt.Errorf("request was empty") } if options.Unmarshal == nil { return nil, fmt.Errorf("unmarshal was empty") } + // Allow missing BodyType only for multipart/form-data requests; otherwise keep existing requirement. + if options.BodyType == nil { + ct := "" + if options.request != nil && options.request.Header != nil { + ct = options.request.Header.Get("Content-Type") + } + isMultipart := false + if ct != "" { + if mediaType, _, err := mime.ParseMediaType(ct); err == nil { + isMultipart = strings.EqualFold(mediaType, "multipart/form-data") + } else { + isMultipart = strings.Contains(strings.ToLower(ct), "multipart/form-data") + } + } + if !isMultipart { + return nil, fmt.Errorf("body type was empty") + } + } var ret = &Body{request: options.request, bodyType: options.BodyType, unmarshal: options.UnmarshalFunc(), form: options.Form} return ret, nil } diff --git a/view/state/kind/locator/http.go b/view/state/kind/locator/http.go index 8fdd0d9bc..62c9ed697 100644 --- a/view/state/kind/locator/http.go +++ b/view/state/kind/locator/http.go @@ -4,11 +4,12 @@ import ( "bytes" "context" "fmt" - "github.com/viant/datly/view/state/kind" "io" "net/http" "reflect" "strings" + + "github.com/viant/datly/view/state/kind" ) type HttpRequest struct { From 66a431862c30d80663d2a3b28a01768714c2d0a4 Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 6 Nov 2025 19:49:52 -0800 Subject: [PATCH 071/117] patched multi content upload --- service/session/stater.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/service/session/stater.go b/service/session/stater.go index c87a6966f..2481d8077 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -101,10 +101,8 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt if s.component != nil && s.component.Input.Type.Type() != nil && s.component.Input.Type.Type().Type() != nil { compInType := s.component.Input.Type.Type().Type() inType := reflect.TypeOf(input) - if inType != nil && inType.Kind() != reflect.Ptr { - inType = reflect.PtrTo(inType) - } - if inType == compInType { + + if inType != nil && compInType != nil && types.EnsureStruct(inType) == types.EnsureStruct(compInType) { parameters = s.component.Input.Type.Parameters } } @@ -112,6 +110,7 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt if len(parameters) == 0 { inType := reflect.TypeOf(input) aType, e := state.NewType( + state.WithFS(embedFs), state.WithSchema(state.NewSchema(inType)), state.WithResource(s.resource), ) From 9ff2695063609beb0eefe9be3230cfa5c21b0c7b Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 7 Nov 2025 08:18:57 -0800 Subject: [PATCH 072/117] patched multi content upload --- internal/inference/parameter.go | 4 +++ service/session/state.go | 4 +++ shared/http.go | 20 +++++++++---- view/state/kind/locator/body.go | 41 +++++++++------------------ view/state/kind/locator/form.go | 50 +++++++++++++++++++++++++++++++-- 5 files changed, 85 insertions(+), 34 deletions(-) diff --git a/internal/inference/parameter.go b/internal/inference/parameter.go index eddb8efe5..ff5e5e68f 100644 --- a/internal/inference/parameter.go +++ b/internal/inference/parameter.go @@ -128,6 +128,10 @@ func (p *Parameter) veltyDeclaration(builder *strings.Builder) { builder.WriteString(".Required()") } } + + if p.Cacheable != nil { + builder.WriteString(".Cacheable('" + strconv.FormatBool(*p.Cacheable) + "')") + } if p.Connector != "" { builder.WriteString(".WithConnector('" + p.Connector + "')") } diff --git a/service/session/state.go b/service/session/state.go index 3f28d36b5..851f274af 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -761,6 +761,10 @@ func (s *Session) LoadState(parameters state.Parameters, aState interface{}) err if parameter.Scope != "" { continue } + // Only warm cache for cacheable parameters; LookupValue only reads cache when cacheable + if !parameter.IsCacheable() { + continue + } selector, _ := inputState.Selector(parameter.Name) if selector == nil { continue diff --git a/shared/http.go b/shared/http.go index 3504c2546..24703bf2b 100644 --- a/shared/http.go +++ b/shared/http.go @@ -18,8 +18,8 @@ func CloneHTTPRequest(request *http.Request) (*http.Request, error) { return &ret, nil } - // Detect multipart/form-data; avoid reading/consuming body - if isMultipartRequest(request) { + // Detect multipart/*; avoid reading/consuming body + if IsMultipartRequest(request) { // share the same Body; caller must ensure only one reader consumes it ret.Body = request.Body return &ret, nil @@ -44,17 +44,27 @@ func readRequestBody(request *http.Request) ([]byte, error) { return data, err } -func isMultipartRequest(r *http.Request) bool { +// IsMultipartRequest returns true if request Content-Type is multipart/* +func IsMultipartRequest(r *http.Request) bool { if r == nil || r.Header == nil { return false } - ct := r.Header.Get("Content-Type") + return IsMultipartContentType(r.Header.Get("Content-Type")) +} + +// IsMultipartContentType returns true when the Content-Type header indicates any multipart/* +func IsMultipartContentType(ct string) bool { if ct == "" { return false } mediaType, _, err := mime.ParseMediaType(ct) if err != nil { - return strings.Contains(strings.ToLower(ct), "multipart/form-data") + return strings.Contains(strings.ToLower(ct), "multipart/") } + return strings.HasPrefix(strings.ToLower(mediaType), "multipart/") +} + +// IsFormData returns true when mediaType equals multipart/form-data +func IsFormData(mediaType string) bool { return strings.EqualFold(mediaType, "multipart/form-data") } diff --git a/view/state/kind/locator/body.go b/view/state/kind/locator/body.go index d0c6c2150..e17af401b 100644 --- a/view/state/kind/locator/body.go +++ b/view/state/kind/locator/body.go @@ -7,7 +7,6 @@ import ( "mime/multipart" "net/http" "reflect" - "strings" "sync" "github.com/viant/datly/shared" @@ -84,13 +83,18 @@ func (r *Body) Value(ctx context.Context, rType reflect.Type, name string) (inte func (r *Body) initOnce() { r.Once.Do(func() { // Multipart branch - if r.request != nil && r.isMultipartRequest() { - r.isMultipart = true - r.err = r.request.ParseMultipartForm(maxMultipartMemory) - if r.err == nil { - r.seedFormFromMultipart() + if r.request != nil { + ct := r.request.Header.Get("Content-Type") + if shared.IsMultipartContentType(ct) { + r.isMultipart = true + if mediaType, _, err := mime.ParseMediaType(ct); err == nil && shared.IsFormData(mediaType) { + r.err = r.request.ParseMultipartForm(maxMultipartMemory) + if r.err == nil { + r.seedFormFromMultipart() + } + } + return } - return } // Non-multipart: clone and read body safely var request *http.Request @@ -162,7 +166,7 @@ func NewBody(opts ...Option) (kind.Locator, error) { if options.Unmarshal == nil { return nil, fmt.Errorf("unmarshal was empty") } - // Allow missing BodyType only for multipart/form-data requests; otherwise keep existing requirement. + // Allow missing BodyType only for multipart/* requests; otherwise keep existing requirement. if options.BodyType == nil { ct := "" if options.request != nil && options.request.Header != nil { @@ -170,11 +174,7 @@ func NewBody(opts ...Option) (kind.Locator, error) { } isMultipart := false if ct != "" { - if mediaType, _, err := mime.ParseMediaType(ct); err == nil { - isMultipart = strings.EqualFold(mediaType, "multipart/form-data") - } else { - isMultipart = strings.Contains(strings.ToLower(ct), "multipart/form-data") - } + isMultipart = shared.IsMultipartContentType(ct) } if !isMultipart { return nil, fmt.Errorf("body type was empty") @@ -235,20 +235,7 @@ func (r *Body) updateQueryString(ctx context.Context, body interface{}) { } // isMultipartRequest checks content type for multipart/form-data -func (r *Body) isMultipartRequest() bool { - if r.request == nil { - return false - } - ct := r.request.Header.Get("Content-Type") - if ct == "" { - return false - } - mediaType, _, err := mime.ParseMediaType(ct) - if err != nil { - return strings.Contains(strings.ToLower(ct), "multipart/form-data") - } - return strings.EqualFold(mediaType, "multipart/form-data") -} +// removed: local isMultipartRequest; use shared.IsMultipartContentType instead // seedFormFromMultipart copies textual multipart values into shared form to avoid re-parsing later func (r *Body) seedFormFromMultipart() { diff --git a/view/state/kind/locator/form.go b/view/state/kind/locator/form.go index 174f66255..ba14605fb 100644 --- a/view/state/kind/locator/form.go +++ b/view/state/kind/locator/form.go @@ -2,15 +2,20 @@ package locator import ( "context" - "github.com/viant/datly/view/state/kind" - "github.com/viant/xdatly/handler/state" + "mime" "net/http" "reflect" + "sync" + + "github.com/viant/datly/shared" + "github.com/viant/datly/view/state/kind" + "github.com/viant/xdatly/handler/state" ) type Form struct { form *state.Form request *http.Request + once sync.Once } func (r *Form) Names() []string { @@ -26,6 +31,18 @@ func (r *Form) Value(ctx context.Context, _ reflect.Type, name string) (interfac if r.request == nil { return nil, false, nil } + // If multipart, seed from multipart and avoid FormValue fallback + if shared.IsMultipartContentType(r.request.Header.Get("Content-Type")) { + r.once.Do(func() { r.seedFormFromMultipart() }) + if values, ok = r.form.Lookup(name); ok { + if len(values) > 1 { + return values, true, nil + } + return r.form.Get(name), true, nil + } + return nil, false, nil + } + // Non-multipart: use standard FormValue fallback r.form.Mutex().Lock() defer r.form.Mutex().Unlock() value := r.request.FormValue(name) @@ -50,3 +67,32 @@ func NewForm(opts ...Option) (kind.Locator, error) { var ret = &Form{form: options.Form, request: options.request} return ret, nil } + +// seedFormFromMultipart parses multipart/form-data (if needed) and copies textual values to the shared form +func (r *Form) seedFormFromMultipart() { + if r.request == nil || r.form == nil { + return + } + if r.request.MultipartForm == nil { + // Only ParseMultipartForm for form-data; other multipart types aren't supported by ParseMultipartForm + ct := r.request.Header.Get("Content-Type") + if ct != "" { + if mediaType, _, err := mime.ParseMediaType(ct); err == nil && shared.IsFormData(mediaType) { + // Use the same default memory threshold as Body locator + const maxMultipartMemory = 32 << 20 // 32 MiB + _ = r.request.ParseMultipartForm(maxMultipartMemory) + } + } + } + if r.request.MultipartForm == nil { + return + } + r.form.Mutex().Lock() + defer r.form.Mutex().Unlock() + for k, vs := range r.request.MultipartForm.Value { + if len(vs) == 0 { + continue + } + r.form.Set(k, vs...) + } +} From f644cf7635d9ab72c15c5bce721a7b0f4c4b591a Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 7 Nov 2025 08:32:43 -0800 Subject: [PATCH 073/117] patched multi content upload --- service/session/state.go | 25 ++++++++++++++++++++++++- service/session/stater.go | 8 +++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/service/session/state.go b/service/session/state.go index 851f274af..68a4ca8e1 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -746,7 +746,27 @@ func New(aView *view.View, opts ...Option) *Session { return ret } -func (s *Session) LoadState(parameters state.Parameters, aState interface{}) error { +type loadStateOptions struct { + skipKind map[state.Kind]bool + hasSkipKind bool +} + +type LoadStateOption func(o *loadStateOptions) + +func WithLoadStateSkipKind(kinds ...state.Kind) LoadStateOption { + return func(o *loadStateOptions) { + for _, kind := range kinds { + o.skipKind[kind] = true + } + } +} + +func (s *Session) LoadState(parameters state.Parameters, aState interface{}, opts ...LoadStateOption) error { + options := &loadStateOptions{skipKind: map[state.Kind]bool{}} + for _, opt := range opts { + opt(options) + } + options.hasSkipKind = len(options.skipKind) > 0 rType := reflect.TypeOf(aState) sType := structology.NewStateType(rType, structology.WithCustomizedNames(func(name string, tag reflect.StructTag) []string { stateTag, _ := tags.ParseStateTags(tag, nil) @@ -761,6 +781,9 @@ func (s *Session) LoadState(parameters state.Parameters, aState interface{}) err if parameter.Scope != "" { continue } + if options.hasSkipKind && options.skipKind[parameter.In.Kind] { + continue + } // Only warm cache for cacheable parameters; LookupValue only reads cache when cacheable if !parameter.IsCacheable() { continue diff --git a/service/session/stater.go b/service/session/stater.go index 2481d8077..cd471fd71 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -122,7 +122,13 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt } parameters = aType.Parameters } - if e := s.LoadState(parameters, input); e != nil { + + var skipOption []LoadStateOption + if s.view.Mode != view.ModeQuery { + skipOption = append(skipOption, WithLoadStateSkipKind(state.KindView, state.KindParam)) + } + + if e := s.LoadState(parameters, input, skipOption...); e != nil { return e } if s.view.Mode == view.ModeQuery { From 115062e8bfd96e5d1addcbae24c8d5d92c395829 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 7 Nov 2025 08:35:44 -0800 Subject: [PATCH 074/117] patched multi content upload --- service/session/stater.go | 1 + 1 file changed, 1 insertion(+) diff --git a/service/session/stater.go b/service/session/stater.go index cd471fd71..ab6889cd5 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -125,6 +125,7 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt var skipOption []LoadStateOption if s.view.Mode != view.ModeQuery { + //this is for patch component only (in the future we may pass it to caller when call Bind skipOption = append(skipOption, WithLoadStateSkipKind(state.KindView, state.KindParam)) } From ecf638371cce89f0efdcab88acf01e8b3d8f0b10 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 7 Nov 2025 16:25:22 -0800 Subject: [PATCH 075/117] patched multi content upload --- service/session/stater.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/session/stater.go b/service/session/stater.go index ab6889cd5..f29cabe0c 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -126,7 +126,7 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt var skipOption []LoadStateOption if s.view.Mode != view.ModeQuery { //this is for patch component only (in the future we may pass it to caller when call Bind - skipOption = append(skipOption, WithLoadStateSkipKind(state.KindView, state.KindParam)) + skipOption = append(skipOption, WithLoadStateSkipKind(state.KindComponent, state.KindView, state.KindParam)) } if e := s.LoadState(parameters, input, skipOption...); e != nil { From d6e71464435c5c4fcbfeefc6c793feb15dec5b50 Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 7 Nov 2025 16:25:57 -0800 Subject: [PATCH 076/117] patched multi content upload --- service/session/stater.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/session/stater.go b/service/session/stater.go index f29cabe0c..635dff901 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -126,7 +126,7 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt var skipOption []LoadStateOption if s.view.Mode != view.ModeQuery { //this is for patch component only (in the future we may pass it to caller when call Bind - skipOption = append(skipOption, WithLoadStateSkipKind(state.KindComponent, state.KindView, state.KindParam)) + skipOption = append(skipOption, WithLoadStateSkipKind(state.KindHeader, state.KindComponent, state.KindView, state.KindParam)) } if e := s.LoadState(parameters, input, skipOption...); e != nil { From d3359f93bed8d9301971b97c116e328a8d7e4699 Mon Sep 17 00:00:00 2001 From: adranwit Date: Sat, 8 Nov 2025 05:53:02 -0800 Subject: [PATCH 077/117] patched multi content upload --- service/session/state.go | 48 +++++++++++++--- service/session/stater.go | 112 +++++++++++++++++++++++--------------- view/state/type.go | 7 +++ 3 files changed, 113 insertions(+), 54 deletions(-) diff --git a/service/session/state.go b/service/session/state.go index 68a4ca8e1..a85680740 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -299,13 +299,21 @@ func (s *Session) populateParameter(ctx context.Context, parameter *state.Parame parameterSelector := parameter.Selector() if options.indirectState || parameterSelector == nil { //p parameterSelector, err = aState.Selector(parameter.Name) - if parameterSelector == nil && parameter.In.Kind == state.KindConst { // TODO do we really need it? - return nil + if parameterSelector == nil { + switch parameter.In.Kind { + case state.KindConst: + return nil + case state.KindRequestBody: + if parameter.In.Name == "" { //auxiliary body wrapper + return nil + } + } } if err != nil { return err } } + if value, err = s.ensureValidValue(value, parameter, parameterSelector, options); err != nil { return err } @@ -564,8 +572,8 @@ func (s *Session) lookupFirstValue(ctx context.Context, parameters []*state.Para } func (s *Session) LookupValue(ctx context.Context, parameter *state.Parameter, opts *Options) (value interface{}, has bool, err error) { - - if value, has, err = s.lookupValue(ctx, parameter, opts); err != nil { + value, has, err = s.lookupValue(ctx, parameter, opts) + if err != nil { err = response.NewParameterError("", parameter.Name, err, response.WithObject(value), response.WithErrorStatusCode(parameter.ErrorStatusCode)) } return value, has, err @@ -656,6 +664,13 @@ func (s *Session) adjustAndCache(ctx context.Context, parameter *state.Parameter return nil, false, err } if parameter.Output != nil { + // Defensive: ensure codec is initialized before Transform. + if !parameter.Output.Initialized() { + // Initialize using session resource and current parameter input type. + if initErr := parameter.Output.Init(s.resource, parameter.Schema.Type()); initErr != nil { + return nil, false, initErr + } + } transformed, err := parameter.Output.Transform(ctx, value, opts.codecOptions...) if err != nil { return nil, false, fmt.Errorf("failed to transform %s with %s: %v, %w", parameter.Name, parameter.Output.Name, value, err) @@ -747,12 +762,18 @@ func New(aView *view.View, opts ...Option) *Session { } type loadStateOptions struct { - skipKind map[state.Kind]bool - hasSkipKind bool + skipKind map[state.Kind]bool + hasSkipKind bool + useHasMarker bool } type LoadStateOption func(o *loadStateOptions) +func WithHasMarker() LoadStateOption { + return func(o *loadStateOptions) { + o.useHasMarker = true + } +} func WithLoadStateSkipKind(kinds ...state.Kind) LoadStateOption { return func(o *loadStateOptions) { for _, kind := range kinds { @@ -777,6 +798,10 @@ func (s *Session) LoadState(parameters state.Parameters, aState interface{}, opt })) inputState := sType.WithValue(aState) ptr := xunsafe.AsPointer(aState) + // Use presence markers only if enabled and supported by the input state + hasMarker := options.useHasMarker && inputState.HasMarker() + bodyParam := parameters.LookupByLocation(state.KindRequestBody, "") + for _, parameter := range parameters { if parameter.Scope != "" { continue @@ -792,23 +817,28 @@ func (s *Session) LoadState(parameters state.Parameters, aState interface{}, opt if selector == nil { continue } - if !selector.Has(ptr) { + // Only use selector.Has when input supports presence markers + if hasMarker && !selector.Has(ptr) { continue } value := selector.Value(ptr) switch parameter.In.Kind { case state.KindView, state.KindParam, state.KindState: if value == nil { - return nil + continue } rType := parameter.OutputType() if rType.Kind() == reflect.Ptr { ptr := (*unsafe.Pointer)(xunsafe.AsPointer(value)) if ptr == nil || *ptr == nil { - return nil + continue } } + case state.KindRequestBody: + if bodyParam != nil { + s.setValue(bodyParam, value) + } } s.setValue(parameter, value) } diff --git a/service/session/stater.go b/service/session/stater.go index 635dff901..bbb763006 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -94,48 +94,6 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt hOptions := hstate.NewOptions(opts...) - // Handle WithInput: preload cache from provided input data - if input := hOptions.Input(); input != nil { - var parameters state.Parameters - // If input type matches component input type, reuse component parameters - if s.component != nil && s.component.Input.Type.Type() != nil && s.component.Input.Type.Type().Type() != nil { - compInType := s.component.Input.Type.Type().Type() - inType := reflect.TypeOf(input) - - if inType != nil && compInType != nil && types.EnsureStruct(inType) == types.EnsureStruct(compInType) { - parameters = s.component.Input.Type.Parameters - } - } - // Otherwise, derive parameters from input type - if len(parameters) == 0 { - inType := reflect.TypeOf(input) - aType, e := state.NewType( - state.WithFS(embedFs), - state.WithSchema(state.NewSchema(inType)), - state.WithResource(s.resource), - ) - if e != nil { - return e - } - if e = aType.Init(); e != nil { - return e - } - parameters = aType.Parameters - } - - var skipOption []LoadStateOption - if s.view.Mode != view.ModeQuery { - //this is for patch component only (in the future we may pass it to caller when call Bind - skipOption = append(skipOption, WithLoadStateSkipKind(state.KindHeader, state.KindComponent, state.KindView, state.KindParam)) - } - - if e := s.LoadState(parameters, input, skipOption...); e != nil { - return e - } - if s.view.Mode == view.ModeQuery { - s.SetViewState(ctx, s.view) - } - } aState := stateType.Type().WithValue(dest) var stateOptions = []locator.Option{ locator.WithLogger(s.logger), @@ -177,23 +135,87 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt viewOptions := s.ViewOptions(s.view, WithLocatorOptions()) stateOptions = append(viewOptions.kindLocator.Options(), stateOptions...) } + if err = s.handleInputState(ctx, hOptions, embedFs); err != nil { + return err + } - if s.component != nil && s.component.Contract.Output.Type.Type().Type() == destType { - return s.handleComponentpOutputType(ctx, dest, stateOptions) + if s.component != nil { + componentOutputType := types.EnsureStruct(s.component.Contract.Output.Type.Type().Type()) + if componentOutputType == types.EnsureStruct(destType) { + return s.handleComponentOutputType(ctx, dest, stateOptions) + } } options := s.Indirect(true, stateOptions...) options.scope = hOptions.Scope() + if err = s.SetState(ctx, stateType.Parameters, aState, options); err != nil { return err } + if initializer, ok := dest.(state.Initializer); ok { err = initializer.Init(ctx) } return err } -func (s *Session) handleComponentpOutputType(ctx context.Context, dest interface{}, stateOptions []locator.Option) error { +func (s *Session) handleInputState(ctx context.Context, hOptions *hstate.Options, embedFs *embed.FS) error { + // Handle WithInput: preload cache from provided input data + if input := hOptions.Input(); input != nil { + var parameters state.Parameters + var inputType *state.Type + // If input type matches component input type, reuse component parameters + if s.component != nil && s.component.Input.Type.Type() != nil && s.component.Input.Type.Type().Type() != nil { + compInType := s.component.Input.Type.Type().Type() + inType := reflect.TypeOf(input) + if inType != nil && compInType != nil && types.EnsureStruct(inType) == types.EnsureStruct(compInType) { + parameters = s.component.Input.Type.Parameters + inputType = &s.component.Input.Type + } + } + // Otherwise, derive parameters from input type + if len(parameters) == 0 { + inType := reflect.TypeOf(input) + aType, e := state.NewType( + state.WithFS(embedFs), + state.WithSchema(state.NewSchema(inType)), + state.WithResource(s.resource), + ) + if e != nil { + return e + } + if e = aType.Init(); e != nil { + return e + } + inputType = aType + for _, p := range aType.Parameters { + p.Init(ctx, s.view.Resource()) + } + parameters = aType.Parameters + } + + var skipOption []LoadStateOption + skipOption = append(skipOption, WithHasMarker()) + if s.view.Mode != view.ModeQuery { + //this is for patch component only (in the future we may pass it to caller when call Bind + skipOption = append(skipOption, WithLoadStateSkipKind(state.KindView, state.KindParam)) + } + if e := s.LoadState(parameters, input, skipOption...); e != nil { + return e + } + if s.view.Mode == view.ModeQuery { + inputState := inputType.Type().WithValue(input) + options := s.Options.Indirect(true) + if err := s.SetState(ctx, parameters, inputState, options); err != nil { + return err + } + _ = s.SetViewState(ctx, s.view) + } + } + return nil +} + +func (s *Session) handleComponentOutputType(ctx context.Context, dest interface{}, stateOptions []locator.Option) error { sessionOpt := s.Options s.Options = *s.Indirect(true, stateOptions...) destValue, err := s.operate(ctx, s, s.component) diff --git a/view/state/type.go b/view/state/type.go index d2ea7c0c2..523e4048e 100644 --- a/view/state/type.go +++ b/view/state/type.go @@ -82,6 +82,13 @@ func (t *Type) Init(options ...Option) (err error) { if err := t.buildParameters(); err != nil { return err } + // Ensure all derived parameters are fully initialized (schema, codecs, etc.). + for _, parameter := range t.Parameters { + t.resource.AppendParameter(parameter) + if err := parameter.Init(context.Background(), t.resource); err != nil { + return err + } + } } else if hasParameters && t.Schema.Type() == nil { if err := t.buildSchema(context.Background(), t.withMarker); err != nil { return err From e9e5ca7e5ba6ef5c15887174c5f883a2c4904d99 Mon Sep 17 00:00:00 2001 From: adranwit Date: Sat, 8 Nov 2025 07:00:00 -0800 Subject: [PATCH 078/117] patched multi content upload --- service/session/state.go | 12 +---- service/session/stater.go | 93 ++++++++++++++++++++------------------- view/state/type.go | 7 --- 3 files changed, 50 insertions(+), 62 deletions(-) diff --git a/service/session/state.go b/service/session/state.go index a85680740..2808c04e1 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -303,10 +303,6 @@ func (s *Session) populateParameter(ctx context.Context, parameter *state.Parame switch parameter.In.Kind { case state.KindConst: return nil - case state.KindRequestBody: - if parameter.In.Name == "" { //auxiliary body wrapper - return nil - } } } if err != nil { @@ -800,15 +796,15 @@ func (s *Session) LoadState(parameters state.Parameters, aState interface{}, opt ptr := xunsafe.AsPointer(aState) // Use presence markers only if enabled and supported by the input state hasMarker := options.useHasMarker && inputState.HasMarker() - bodyParam := parameters.LookupByLocation(state.KindRequestBody, "") - for _, parameter := range parameters { if parameter.Scope != "" { continue } + if options.hasSkipKind && options.skipKind[parameter.In.Kind] { continue } + // Only warm cache for cacheable parameters; LookupValue only reads cache when cacheable if !parameter.IsCacheable() { continue @@ -835,10 +831,6 @@ func (s *Session) LoadState(parameters state.Parameters, aState interface{}, opt continue } } - case state.KindRequestBody: - if bodyParam != nil { - s.setValue(bodyParam, value) - } } s.setValue(parameter, value) } diff --git a/service/session/stater.go b/service/session/stater.go index bbb763006..332c0206c 100644 --- a/service/session/stater.go +++ b/service/session/stater.go @@ -135,6 +135,7 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt viewOptions := s.ViewOptions(s.view, WithLocatorOptions()) stateOptions = append(viewOptions.kindLocator.Options(), stateOptions...) } + if err = s.handleInputState(ctx, hOptions, embedFs); err != nil { return err } @@ -161,56 +162,58 @@ func (s *Session) Bind(ctx context.Context, dest interface{}, opts ...hstate.Opt func (s *Session) handleInputState(ctx context.Context, hOptions *hstate.Options, embedFs *embed.FS) error { // Handle WithInput: preload cache from provided input data - if input := hOptions.Input(); input != nil { - var parameters state.Parameters - var inputType *state.Type - // If input type matches component input type, reuse component parameters - if s.component != nil && s.component.Input.Type.Type() != nil && s.component.Input.Type.Type().Type() != nil { - compInType := s.component.Input.Type.Type().Type() - inType := reflect.TypeOf(input) - if inType != nil && compInType != nil && types.EnsureStruct(inType) == types.EnsureStruct(compInType) { - parameters = s.component.Input.Type.Parameters - inputType = &s.component.Input.Type - } + input := hOptions.Input() + if input == nil { + return nil + } + var parameters state.Parameters + var inputType *state.Type + // If input type matches component input type, reuse component parameters + if s.component != nil && s.component.Input.Type.Type() != nil && s.component.Input.Type.Type().Type() != nil { + compInType := s.component.Input.Type.Type().Type() + inType := reflect.TypeOf(input) + if inType != nil && compInType != nil && types.EnsureStruct(inType) == types.EnsureStruct(compInType) { + parameters = s.component.Input.Type.Parameters + inputType = &s.component.Input.Type } - // Otherwise, derive parameters from input type - if len(parameters) == 0 { - inType := reflect.TypeOf(input) - aType, e := state.NewType( - state.WithFS(embedFs), - state.WithSchema(state.NewSchema(inType)), - state.WithResource(s.resource), - ) - if e != nil { - return e - } - if e = aType.Init(); e != nil { - return e - } - inputType = aType - for _, p := range aType.Parameters { - p.Init(ctx, s.view.Resource()) - } - parameters = aType.Parameters - } - - var skipOption []LoadStateOption - skipOption = append(skipOption, WithHasMarker()) - if s.view.Mode != view.ModeQuery { - //this is for patch component only (in the future we may pass it to caller when call Bind - skipOption = append(skipOption, WithLoadStateSkipKind(state.KindView, state.KindParam)) + } + // Otherwise, derive parameters from input type + if len(parameters) == 0 { + inType := reflect.TypeOf(input) + aType, e := state.NewType( + state.WithFS(embedFs), + state.WithSchema(state.NewSchema(inType)), + state.WithResource(s.resource), + ) + if e != nil { + return e } - if e := s.LoadState(parameters, input, skipOption...); e != nil { + if e = aType.Init(); e != nil { return e } - if s.view.Mode == view.ModeQuery { - inputState := inputType.Type().WithValue(input) - options := s.Options.Indirect(true) - if err := s.SetState(ctx, parameters, inputState, options); err != nil { - return err - } - _ = s.SetViewState(ctx, s.view) + inputType = aType + for _, p := range aType.Parameters { + p.Init(ctx, s.view.Resource()) + } + parameters = aType.Parameters + } + + var skipOption []LoadStateOption + skipOption = append(skipOption, WithHasMarker()) + if s.view.Mode != view.ModeQuery { + //this is for patch component only (in the future we may pass it to caller when call Bind + skipOption = append(skipOption, WithLoadStateSkipKind(state.KindView, state.KindParam)) + } + if e := s.LoadState(parameters, input, skipOption...); e != nil { + return e + } + if s.view.Mode == view.ModeQuery { + inputState := inputType.Type().WithValue(input) + options := s.Options.Indirect(true) + if err := s.SetState(ctx, parameters, inputState, options); err != nil { + return err } + _ = s.SetViewState(ctx, s.view) } return nil } diff --git a/view/state/type.go b/view/state/type.go index 523e4048e..d2ea7c0c2 100644 --- a/view/state/type.go +++ b/view/state/type.go @@ -82,13 +82,6 @@ func (t *Type) Init(options ...Option) (err error) { if err := t.buildParameters(); err != nil { return err } - // Ensure all derived parameters are fully initialized (schema, codecs, etc.). - for _, parameter := range t.Parameters { - t.resource.AppendParameter(parameter) - if err := parameter.Init(context.Background(), t.resource); err != nil { - return err - } - } } else if hasParameters && t.Schema.Type() == nil { if err := t.buildSchema(context.Background(), t.withMarker); err != nil { return err From 889497e415ba029fb0d93e328fbc40ab16867ffa Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 13 Nov 2025 10:13:37 -0800 Subject: [PATCH 079/117] patched multi content upload --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 6ae51f459..5a044b2b5 100644 --- a/go.mod +++ b/go.mod @@ -53,9 +53,9 @@ require ( github.com/viant/mcp-protocol v0.5.10 github.com/viant/structology v0.6.1 github.com/viant/tagly v0.2.2 - github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa + github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 - github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e + github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a github.com/viant/xlsy v0.3.1 diff --git a/go.sum b/go.sum index f427f0da7..22401582d 100644 --- a/go.sum +++ b/go.sum @@ -1166,6 +1166,8 @@ github.com/viant/x v0.3.0 h1:/3A0z/uySGxMo6ixH90VAcdjI00w5e3REC1zg5hzhJA= github.com/viant/x v0.3.0/go.mod h1:54jP3qV+nnQdNDaWxEwGTAAzCu9sx9er9htiwTW/Mcw= github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa h1:o5o1CmraGb/LSpfrgmDoMdi9JJGjiopH8cmX98ukJS0= github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= +github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a h1:7CLO2LjVnFgOwN0FL3Q4y5NrD7DpclS21AiW6tDLIc8= +github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 h1:9Yry3PUBDzc4rWacOYvAq/TKrTV0agvMF0gwm2gaoHI= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259/go.mod h1:fb8YgbVadk8X5ZLz49LWGzWmQlZd7Y/I5wE0ru44bIo= github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa h1:UzX1wB23RMENSKF5X0fQZR/cIy7wB7z2ODWCIm358IQ= @@ -1174,6 +1176,8 @@ github.com/viant/xdatly/handler v0.0.0-20251101181445-c75586bb6ea4 h1:qlYPNwGIfe github.com/viant/xdatly/handler v0.0.0-20251101181445-c75586bb6ea4/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e h1:WJb6NjQP/84Fqovpesy6TqST2ukHLFF+lTI9Vz43O5I= github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= +github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a h1:ofcLA78XVzYW0lKkmVxix00JFANZXh2JTvrzFlM/BS8= +github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 h1:G+e1MMDxQXUPPlAXVNlRqSLTLra7udGQZUu3hnr0Y8M= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52/go.mod h1:LJN2m8xJjtYNCvyvNrVanJwvzj8+hYCuPswL8H4qRG0= github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a h1:jecH7mH63gj1zJwD18SdvSHM9Ttr9FEOnhHkYfkCNkI= From 8654c5cf10158c8a3220ca2ba72d1c61b01ef9c0 Mon Sep 17 00:00:00 2001 From: ppoudyal Date: Fri, 21 Nov 2025 16:08:52 -0500 Subject: [PATCH 080/117] slice interface type cast fixed --- service/session/selector.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/service/session/selector.go b/service/session/selector.go index e4a39b8d3..11c700c16 100644 --- a/service/session/selector.go +++ b/service/session/selector.go @@ -231,7 +231,19 @@ func (s *Session) setFieldsQuerySelector(value interface{}, ns *view.NamespaceVi return fmt.Errorf("can't use projection on view %v", ns.View.Name) } selector := s.state.Lookup(ns.View) - fields := value.([]string) + var fields []string + switch v := value.(type) { + case []string: + fields = v + case []interface{}: + for _, elem := range v { + text, ok := elem.(string) + if !ok { + continue + } + fields = append(fields, text) + } + } for _, field := range fields { fieldName := ns.View.CaseFormat.Format(field, text.CaseFormatUpperCamel) if err = canUseColumn(ns.View, fieldName); err != nil { From d7474f76cae3c58591fb17155bbbee9a37ae8467 Mon Sep 17 00:00:00 2001 From: adranwit Date: Sat, 22 Nov 2025 05:59:48 -0800 Subject: [PATCH 081/117] patched multi content upload --- go.mod | 6 ++--- go.sum | 28 +++++---------------- shared/http.go | 23 +++++++++++++++++- view/state/kind/locator/form.go | 43 +++++++++++++++++++++++++++++---- 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 5a044b2b5..b34d19359 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/viant/dyndb v0.1.4-0.20221214043424-27654ab6ed9c github.com/viant/gmetric v0.3.2 github.com/viant/godiff v0.4.1 - github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b + github.com/viant/parsly v0.3.3 github.com/viant/pgo v0.11.0 github.com/viant/scy v0.24.0 github.com/viant/sqlx v0.17.8 @@ -51,8 +51,8 @@ require ( github.com/viant/jsonrpc v0.15.0 github.com/viant/mcp v0.8.0 github.com/viant/mcp-protocol v0.5.10 - github.com/viant/structology v0.6.1 - github.com/viant/tagly v0.2.2 + github.com/viant/structology v0.8.0 + github.com/viant/tagly v0.3.0 github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a diff --git a/go.sum b/go.sum index 22401582d..ea4bdaa33 100644 --- a/go.sum +++ b/go.sum @@ -1124,24 +1124,14 @@ github.com/viant/govalidator v0.3.1 h1:V7f/KgfzbP8fVDc+Kj+jyPvfXxMr2N1x7srOlDV6l github.com/viant/govalidator v0.3.1/go.mod h1:D35Dwx0R8rR1knRxhlseoYvOkiqo24kpMg1/o977i9Y= github.com/viant/igo v0.2.0 h1:ygWmTCinnGPaeV7omJLiyneOpzYZ5kiw7oYz7mUJZVQ= github.com/viant/igo v0.2.0/go.mod h1:7V6AWsLhKWeGzXNTNH3AZiIEKa0m33DrQbdWtapsI74= -github.com/viant/jsonrpc v0.11.0 h1:SqOztRwLWTCdK+VSU0XhZvwqeHrJ1hpQcmhPY6NXH5g= -github.com/viant/jsonrpc v0.11.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= -github.com/viant/jsonrpc v0.14.0 h1:YppPzIidbd9bgjKHCREXkvjkJXf8AaFGGWfk1r+nCJE= -github.com/viant/jsonrpc v0.14.0/go.mod h1:LW2l5/H4KkGCsx2ktPX59iUlycw85ZlBcRuK/WYWBX8= github.com/viant/jsonrpc v0.15.0 h1:0qy9vzgNwR9Gj1C+ouSrzNUtNDzKGogO+7TZR+cFrA4= github.com/viant/jsonrpc v0.15.0/go.mod h1:b214Lo4zBwLqbu6Tf2bRlgQkFfPMBW5ap4qS+I3zcJ8= -github.com/viant/mcp v0.7.0 h1:pIsT93/45pDxpphsZgS8d+0mIzNDihZH0zCDADxGqe8= -github.com/viant/mcp v0.7.0/go.mod h1:4Kk48IEvnAwkplg9sLs1lOBY3cRdsYjrn4lXXdPOPMo= -github.com/viant/mcp v0.7.2 h1:+vkzxFIlKWsjTY/56oBcHuPBlO+9lNb1cwwm2FXA/cA= -github.com/viant/mcp v0.7.2/go.mod h1:4Kk48IEvnAwkplg9sLs1lOBY3cRdsYjrn4lXXdPOPMo= -github.com/viant/mcp v0.7.5 h1:8Gmdz4LiZ1Ot8eUaLCufqWtivrkGGjBA1ra41cdmgmo= -github.com/viant/mcp v0.7.5/go.mod h1:3eBNG5U/CCOPbLdBpF3clwS11WfxEYB6MdzTL2s4jLo= github.com/viant/mcp v0.8.0 h1:n4tnLXpOtpnrLZtHyNG2mmZ9SUbGWKsWGla10iMfuDg= github.com/viant/mcp v0.8.0/go.mod h1:fyuB1TSQYbbGNn7U6rLmlr9gD+Yg5+Na32D34Uvm0sk= github.com/viant/mcp-protocol v0.5.10 h1:915EC1GKgBbyYF4efzRSZ/AE6f4vobkbwa2qe6OOjJ0= github.com/viant/mcp-protocol v0.5.10/go.mod h1:EJPomVw6jnI+4Aa2ONYC3WTvApiF0YeQIiaaEpA54ec= -github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28= -github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b/go.mod h1:85fneXJbErKMGhSQto3A5ElTQCwl3t74U9cSV0waBHw= +github.com/viant/parsly v0.3.3 h1:7ytgfLOG4Ils+wviGacWxRD0gAUvVEH/iGsSE+UI8YM= +github.com/viant/parsly v0.3.3/go.mod h1:85fneXJbErKMGhSQto3A5ElTQCwl3t74U9cSV0waBHw= github.com/viant/pgo v0.11.0 h1:PNuYVhwTfyrAHGBO6lxaMFuHP4NkjKV8ULecz3OWk8c= github.com/viant/pgo v0.11.0/go.mod h1:MFzHmkRFZlciugEgUvpl/3grK789PBSH4dUVSLOSo+Q= github.com/viant/scy v0.24.0 h1:KAC3IUARkQxTNSuwBK2YhVBJMOOLN30YaLKHbbuSkMU= @@ -1152,10 +1142,12 @@ github.com/viant/sqlx v0.17.8 h1:YxGTrXC2B1JmDz1qp8G+G9hGPk7XCRevWN1E4E+ZlCI= github.com/viant/sqlx v0.17.8/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= github.com/viant/structology v0.6.1/go.mod h1:63XfkzUyNw7wdi99HJIsH2Rg3d5AOumqbWLUYytOkxU= +github.com/viant/structology v0.8.0 h1:WKdK67l+O1eqsubn8PWMhWcgspUGJ22SgJxUMfiRgqE= +github.com/viant/structology v0.8.0/go.mod h1:Fnm1DyR4gfyPbnhBMkQB5lR6/isYDnncBFO1nCxxmqs= github.com/viant/structql v0.5.3 h1:QeOxvF0so8VFGt5bm+Jr6FL8uRnXkvwWY+ZCkbe3zsI= github.com/viant/structql v0.5.3/go.mod h1:nm9AYnAuSKH7b7pG+dKVxbQrr1Mgp1CQEMvUwwkE+I8= -github.com/viant/tagly v0.2.2 h1:qqb4Dov83i7nl7Gewph/lLaYAF8MKv0N7y34scgRNmE= -github.com/viant/tagly v0.2.2/go.mod h1:vV8QgJkhug+X+qyKds8av0fhjD+4u7IhNtowL1KGQ5A= +github.com/viant/tagly v0.3.0 h1:Y8IckveeSrroR8yisq4MBdxhcNqf4v8II01uCpamh4E= +github.com/viant/tagly v0.3.0/go.mod h1:PauQQkHmAvL5lFGr4gIgi+PE0aUPggBIBYN34sX2Oes= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/viant/toolbox v0.34.5/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/viant/toolbox v0.37.0 h1:+zwSdbQh6I6ZEyxokQJr+1gQKbLEw6erc+Av5dwKtLU= @@ -1164,18 +1156,10 @@ github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 h1:zKk+6hqUipkJXCPCH github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85/go.mod h1:Q/UXviI2Nli8WROEpYd/BELMCSvnulQeyNrbPmMiS/Y= github.com/viant/x v0.3.0 h1:/3A0z/uySGxMo6ixH90VAcdjI00w5e3REC1zg5hzhJA= github.com/viant/x v0.3.0/go.mod h1:54jP3qV+nnQdNDaWxEwGTAAzCu9sx9er9htiwTW/Mcw= -github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa h1:o5o1CmraGb/LSpfrgmDoMdi9JJGjiopH8cmX98ukJS0= -github.com/viant/xdatly v0.5.4-0.20251006174948-cb34263ae8aa/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a h1:7CLO2LjVnFgOwN0FL3Q4y5NrD7DpclS21AiW6tDLIc8= github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 h1:9Yry3PUBDzc4rWacOYvAq/TKrTV0agvMF0gwm2gaoHI= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259/go.mod h1:fb8YgbVadk8X5ZLz49LWGzWmQlZd7Y/I5wE0ru44bIo= -github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa h1:UzX1wB23RMENSKF5X0fQZR/cIy7wB7z2ODWCIm358IQ= -github.com/viant/xdatly/handler v0.0.0-20251006174948-cb34263ae8aa/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= -github.com/viant/xdatly/handler v0.0.0-20251101181445-c75586bb6ea4 h1:qlYPNwGIfejalMBSoLFhpgNk0LZMRFL6NRfQnpetjPc= -github.com/viant/xdatly/handler v0.0.0-20251101181445-c75586bb6ea4/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= -github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e h1:WJb6NjQP/84Fqovpesy6TqST2ukHLFF+lTI9Vz43O5I= -github.com/viant/xdatly/handler v0.0.0-20251101182009-653093ed869e/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a h1:ofcLA78XVzYW0lKkmVxix00JFANZXh2JTvrzFlM/BS8= github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 h1:G+e1MMDxQXUPPlAXVNlRqSLTLra7udGQZUu3hnr0Y8M= diff --git a/shared/http.go b/shared/http.go index 24703bf2b..6be311b52 100644 --- a/shared/http.go +++ b/shared/http.go @@ -20,7 +20,28 @@ func CloneHTTPRequest(request *http.Request) (*http.Request, error) { // Detect multipart/*; avoid reading/consuming body if IsMultipartRequest(request) { - // share the same Body; caller must ensure only one reader consumes it + // If multipart form has already been parsed, we don't need to + // share or re-read the body. Instead, reuse the parsed form and + // multipart data on the clone so that downstream logic can access + // form values without touching the body again. + if request.MultipartForm != nil { + // Body is no longer needed for form access. + ret.Body = http.NoBody + // Reuse parsed forms and multipart metadata. + ret.MultipartForm = request.MultipartForm + if request.Form != nil { + ret.Form = request.Form + } + if request.PostForm != nil { + ret.PostForm = request.PostForm + } + + return &ret, nil + } + + // Backwards compatibility: if the multipart form hasn't been + // parsed yet, fall back to sharing the body. Callers must + // still ensure only one reader consumes it. ret.Body = request.Body return &ret, nil } diff --git a/view/state/kind/locator/form.go b/view/state/kind/locator/form.go index ba14605fb..2b9190533 100644 --- a/view/state/kind/locator/form.go +++ b/view/state/kind/locator/form.go @@ -3,7 +3,9 @@ package locator import ( "context" "mime" + "mime/multipart" "net/http" + "net/url" "reflect" "sync" @@ -22,10 +24,37 @@ func (r *Form) Names() []string { return nil } -func (r *Form) Value(ctx context.Context, _ reflect.Type, name string) (interface{}, bool, error) { +func (r *Form) Value(ctx context.Context, rType reflect.Type, name string) (interface{}, bool, error) { if r.form != nil && len(r.form.Values) == 0 && r.request == nil { return nil, false, nil } + + // Support file uploads when parameters are declared with kind=form + // and types *multipart.FileHeader or []*multipart.FileHeader. This + // aligns multipart file fields with form semantics instead of body. + if r.request != nil && shared.IsMultipartContentType(r.request.Header.Get("Content-Type")) && rType != nil { + // Parse/seed multipart values only once + r.once.Do(func() { r.seedFormFromMultipart() }) + if r.request.MultipartForm != nil { + // []*multipart.FileHeader + if rType.Kind() == reflect.Slice && rType.Elem() == reflect.TypeOf((*multipart.FileHeader)(nil)) { + files := r.request.MultipartForm.File[name] + if len(files) == 0 { + return nil, false, nil + } + return files, true, nil + } + // *multipart.FileHeader + if rType == reflect.TypeOf((*multipart.FileHeader)(nil)) { + files := r.request.MultipartForm.File[name] + if len(files) == 0 { + return nil, false, nil + } + return files[0], true, nil + } + } + } + values, ok := r.form.Lookup(name) if !ok { if r.request == nil { @@ -73,8 +102,10 @@ func (r *Form) seedFormFromMultipart() { if r.request == nil || r.form == nil { return } - if r.request.MultipartForm == nil { - // Only ParseMultipartForm for form-data; other multipart types aren't supported by ParseMultipartForm + if r.request.MultipartForm == nil && len(r.form.Values) == 0 { + // Only ParseMultipartForm for form-data; other multipart types aren't + // supported by ParseMultipartForm. If the shared form already has + // values, treat it as authoritative and avoid parsing. ct := r.request.Header.Get("Content-Type") if ct != "" { if mediaType, _, err := mime.ParseMediaType(ct); err == nil && shared.IsFormData(mediaType) { @@ -87,12 +118,14 @@ func (r *Form) seedFormFromMultipart() { if r.request.MultipartForm == nil { return } - r.form.Mutex().Lock() - defer r.form.Mutex().Unlock() + if len(r.request.Form) == 0 { + r.request.Form = url.Values{} + } for k, vs := range r.request.MultipartForm.Value { if len(vs) == 0 { continue } r.form.Set(k, vs...) + r.request.Form[k] = vs } } From 6e2e58e57a9bb8fee94a05f6d4bc6a9b15f1cf38 Mon Sep 17 00:00:00 2001 From: adranwit Date: Sat, 22 Nov 2025 14:08:11 -0800 Subject: [PATCH 082/117] patched type pointers --- internal/inference/parameter.go | 7 ++++--- internal/inference/state.go | 21 +++++++++++++++------ internal/inference/type.go | 10 ++++++---- view/state/parameters.go | 7 ++++--- view/state/type.go | 12 +++++++++--- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/internal/inference/parameter.go b/internal/inference/parameter.go index ff5e5e68f..9ab895711 100644 --- a/internal/inference/parameter.go +++ b/internal/inference/parameter.go @@ -80,18 +80,19 @@ func (p *Parameter) veltyDeclaration(builder *strings.Builder) { case state.KindParam: builder.WriteString("?") default: + isPtr := strings.HasPrefix(p.Schema.DataType, "*") if p.Schema.Cardinality == state.Many { builder.WriteString("[]") - switch p.In.Kind { case "query", "form", "header": default: - if !p.IsRequired() { + if !p.IsRequired() && !isPtr { + isPtr = true builder.WriteString("*") } } - } else if !p.IsRequired() { + } else if !p.IsRequired() && !isPtr { builder.WriteString("*") } builder.WriteString(p.Schema.DataType) diff --git a/internal/inference/state.go b/internal/inference/state.go index e00c2b3b0..2783c2767 100644 --- a/internal/inference/state.go +++ b/internal/inference/state.go @@ -3,6 +3,12 @@ package inference import ( "context" "fmt" + "go/ast" + "go/parser" + "path" + "reflect" + "strings" + "github.com/viant/afs" "github.com/viant/afs/embed" "github.com/viant/afs/file" @@ -19,11 +25,6 @@ import ( "github.com/viant/toolbox/data" "github.com/viant/xreflect" "github.com/viant/xunsafe" - "go/ast" - "go/parser" - "path" - "reflect" - "strings" ) // State defines datly view/resource parameters @@ -691,12 +692,20 @@ func NewState(packageLocation, dataType string, types *xreflect.Types) (State, e } state.BuildPredicate(aTag, ¶m.Parameter) state.BuildCodec(aTag, ¶m.Parameter) + if param.Schema.DataType == "" { compType := param.Schema.CompType() + paramTypeName := compType.String() + if compType.Kind() == reflect.Pointer { compType = compType.Elem() + paramTypeName := compType.String() + + if compType.Kind() == reflect.Struct { + paramTypeName = "*" + paramTypeName + } } - param.Schema.DataType = compType.String() + param.Schema.DataType = paramTypeName param.Schema.PackagePath = compType.PkgPath() } //} diff --git a/internal/inference/type.go b/internal/inference/type.go index 3694aea03..3982045b4 100644 --- a/internal/inference/type.go +++ b/internal/inference/type.go @@ -229,11 +229,13 @@ func NewType(packageName string, name string, rType reflect.Type) (*Type, error) rType = types.EnsureStruct(rType) if rType.NumField() == 1 { wrapperField := rType.Field(0) - if canidateType, _ := wrapperField.Tag.Lookup("typeName"); canidateType != "" { - name = canidateType + if types.EnsureStruct(wrapperField.Type) != nil { + if canidateType, _ := wrapperField.Tag.Lookup("typeName"); canidateType != "" { + name = canidateType + } + structType := types.EnsureStruct(wrapperField.Type) + return NewType(packageName, name, structType) } - structType := types.EnsureStruct(wrapperField.Type) - return NewType(packageName, name, structType) } for i := 0; i < rType.NumField(); i++ { diff --git a/view/state/parameters.go b/view/state/parameters.go index 0b503b84a..ff409d1e4 100644 --- a/view/state/parameters.go +++ b/view/state/parameters.go @@ -2,6 +2,10 @@ package state import ( "fmt" + "net/http" + "reflect" + "strings" + "github.com/viant/datly/internal/setter" "github.com/viant/datly/shared" "github.com/viant/datly/utils/types" @@ -13,9 +17,6 @@ import ( "github.com/viant/velty" "github.com/viant/xreflect" "github.com/viant/xunsafe" - "net/http" - "reflect" - "strings" ) const ( diff --git a/view/state/type.go b/view/state/type.go index d2ea7c0c2..262a83959 100644 --- a/view/state/type.go +++ b/view/state/type.go @@ -4,6 +4,10 @@ import ( "context" "embed" "fmt" + "reflect" + "strings" + "unicode" + "github.com/viant/datly/internal/setter" "github.com/viant/datly/utils/types" "github.com/viant/datly/view/extension" @@ -11,9 +15,6 @@ import ( "github.com/viant/structology" "github.com/viant/tagly/format/text" "github.com/viant/xreflect" - "reflect" - "strings" - "unicode" ) type ( @@ -265,11 +266,16 @@ func BuildSchema(field *reflect.StructField, pTag *tags.Parameter, result *Param isSlice = true rawType = rawType.Elem() } + isPtr := false if rawType.Kind() == reflect.Ptr { rawType = rawType.Elem() + isPtr = true } rawName := rawType.Name() + if isPtr { + rawName = "*" + rawName + } if pTag.Cardinality != "" { result.ensureSchema() result.Schema.Cardinality = Cardinality(pTag.Cardinality) From dde0e0e7659036274b60ece530e9461551f101be Mon Sep 17 00:00:00 2001 From: ppoudyal Date: Mon, 24 Nov 2025 11:13:22 -0500 Subject: [PATCH 083/117] limit type cast modified to include other primitives than int. --- service/session/selector.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/service/session/selector.go b/service/session/selector.go index 11c700c16..467f26003 100644 --- a/service/session/selector.go +++ b/service/session/selector.go @@ -209,7 +209,10 @@ func (s *Session) setLimitQuerySelector(value interface{}, ns *view.NamespaceVie return fmt.Errorf("can't use Limit on view %v", ns.View.Name) } selector := s.state.Lookup(ns.View) - limit := value.(int) + limit, err := toInt(value) + if err != nil { + return fmt.Errorf("invalid limit value: %v", err) + } if limit <= ns.View.Selector.Limit || ns.View.Selector.Limit == 0 { selector.Limit = limit } @@ -290,3 +293,20 @@ func canUseColumn(aView *view.View, columnName string) error { } return nil } + +func toInt(v interface{}) (int, error) { + switch val := v.(type) { + case int: + return val, nil + case int32: + return int(val), nil + case int64: + return int(val), nil + case float64: + return int(val), nil + case float32: + return int(val), nil + default: + return 0, fmt.Errorf("unsupported type: %T", v) + } +} From 1e7d51171482a1638e35ab7c8e5ea2310ced2e71 Mon Sep 17 00:00:00 2001 From: ppoudyal Date: Mon, 24 Nov 2025 11:14:22 -0500 Subject: [PATCH 084/117] limit type cast modified to include other primitives than int. --- cmd/cli.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/cli.go b/cmd/cli.go index 166f1d8f7..c2455c126 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -3,13 +3,13 @@ package cmd import ( "context" "fmt" + "github.com/jessevdk/go-flags" "github.com/viant/datly/cmd/command" soptions "github.com/viant/datly/cmd/options" ) func RunApp(version string, args soptions.Arguments) error { - options, err := buildOptions(args) if err != nil { return err From 06dba531207d0f81152f4d3df99c28b4e2dcfcf7 Mon Sep 17 00:00:00 2001 From: vagarwal-viant Date: Tue, 25 Nov 2025 11:14:31 -0800 Subject: [PATCH 085/117] ENG-51724 add safe guards across marshalling for deeper dive into panic --- repository/logging/logging.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/repository/logging/logging.go b/repository/logging/logging.go index 00440ac60..8bea12fa4 100644 --- a/repository/logging/logging.go +++ b/repository/logging/logging.go @@ -15,8 +15,8 @@ func Log(config *Config, execContext *exec.Context) { execContext.Metrics = execContext.Metrics.HideMetrics() } if config.IsAuditEnabled() { - data, _ := json.Marshal(execContext) - fmt.Println("[AUDIT] " + string(data)) + data := safeMarshal("EXECCONTEXT", execContext) + fmt.Println("[AUDIT]", string(data)) } if config.IsTracingEnabled() { trace := execContext.Trace @@ -42,7 +42,21 @@ func Log(config *Config, execContext *exec.Context) { } else { trace.Spans[0].SetStatusFromHTTPCode(execContext.StatusCode) } - traceData, _ := json.Marshal(trace) - fmt.Println("[TRACE] " + string(traceData)) + traceData := safeMarshal("TRACE", trace) + fmt.Println("[TRACE]", string(traceData)) } } + +func safeMarshal(label string, v any) []byte { + defer func() { + if r := recover(); r != nil { + fmt.Printf("[LOG-MARSHAL-PANIC] label=%s type=%T panic=%v\n", label, v, r) + } + }() + data, err := json.Marshal(v) + if err != nil { + fmt.Printf("[LOG-MARSHAL-ERROR] label=%s type=%T err=%v\n", label, v, err) + return nil + } + return data +} From 728c9e43d0ec7dace385761e6888d62a11f7481a Mon Sep 17 00:00:00 2001 From: Terry Zhao Date: Tue, 25 Nov 2025 11:57:19 -0800 Subject: [PATCH 086/117] add safeMarshal in the logging --- repository/logging/logging.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/repository/logging/logging.go b/repository/logging/logging.go index 00440ac60..5dc76e96b 100644 --- a/repository/logging/logging.go +++ b/repository/logging/logging.go @@ -3,9 +3,10 @@ package logging import ( "encoding/json" "fmt" - "github.com/viant/xdatly/handler/exec" "strconv" "time" + + "github.com/viant/xdatly/handler/exec" ) func Log(config *Config, execContext *exec.Context) { @@ -15,8 +16,8 @@ func Log(config *Config, execContext *exec.Context) { execContext.Metrics = execContext.Metrics.HideMetrics() } if config.IsAuditEnabled() { - data, _ := json.Marshal(execContext) - fmt.Println("[AUDIT] " + string(data)) + data := safeMarshal("EXECCONTEXT", execContext) + fmt.Println("[AUDIT]", string(data)) } if config.IsTracingEnabled() { trace := execContext.Trace @@ -42,7 +43,21 @@ func Log(config *Config, execContext *exec.Context) { } else { trace.Spans[0].SetStatusFromHTTPCode(execContext.StatusCode) } - traceData, _ := json.Marshal(trace) - fmt.Println("[TRACE] " + string(traceData)) + traceData := safeMarshal("TRACE", trace) + fmt.Println("[TRACE]", string(traceData)) + } +} + +func safeMarshal(label string, v any) []byte { + defer func() { + if r := recover(); r != nil { + fmt.Printf("[LOG-MARSHAL-PANIC] label=%s type=%T panic=%v\n", label, v, r) + } + }() + data, err := json.Marshal(v) + if err != nil { + fmt.Printf("[LOG-MARSHAL-ERROR] label=%s type=%T err=%v\n", label, v, err) + return nil } + return data } From 3d6b55bc5652330e5043bfb54025900dfa41a234 Mon Sep 17 00:00:00 2001 From: Himanshu Shishir Shah Date: Tue, 2 Dec 2025 13:38:53 -0800 Subject: [PATCH 087/117] ENG-52439: using AppendMetrics with mutex lock; updating logging with more info --- go.mod | 2 +- go.sum | 6 ++---- repository/logging/logging.go | 33 ++++++++++++++++++++++++++++++++- service/executor/service.go | 2 +- service/reader/service.go | 2 +- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index b34d19359..82524a2fb 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( github.com/viant/tagly v0.3.0 github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 - github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a + github.com/viant/xdatly/handler v0.0.0-20251202205015-5f121a805ed3 github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a github.com/viant/xlsy v0.3.1 diff --git a/go.sum b/go.sum index ea4bdaa33..c9b72c11c 100644 --- a/go.sum +++ b/go.sum @@ -1140,8 +1140,6 @@ github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= github.com/viant/sqlx v0.17.8 h1:YxGTrXC2B1JmDz1qp8G+G9hGPk7XCRevWN1E4E+ZlCI= github.com/viant/sqlx v0.17.8/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= -github.com/viant/structology v0.6.1 h1:Forza+RF/1tmlQFk9ABNhu+IQ8vMAqbYM6FOsYtGh9E= -github.com/viant/structology v0.6.1/go.mod h1:63XfkzUyNw7wdi99HJIsH2Rg3d5AOumqbWLUYytOkxU= github.com/viant/structology v0.8.0 h1:WKdK67l+O1eqsubn8PWMhWcgspUGJ22SgJxUMfiRgqE= github.com/viant/structology v0.8.0/go.mod h1:Fnm1DyR4gfyPbnhBMkQB5lR6/isYDnncBFO1nCxxmqs= github.com/viant/structql v0.5.3 h1:QeOxvF0so8VFGt5bm+Jr6FL8uRnXkvwWY+ZCkbe3zsI= @@ -1160,8 +1158,8 @@ github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a h1:7CLO2LjVnFgOwN0F github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 h1:9Yry3PUBDzc4rWacOYvAq/TKrTV0agvMF0gwm2gaoHI= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259/go.mod h1:fb8YgbVadk8X5ZLz49LWGzWmQlZd7Y/I5wE0ru44bIo= -github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a h1:ofcLA78XVzYW0lKkmVxix00JFANZXh2JTvrzFlM/BS8= -github.com/viant/xdatly/handler v0.0.0-20251113181159-0ac8b8b0ff3a/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= +github.com/viant/xdatly/handler v0.0.0-20251202205015-5f121a805ed3 h1:Xw0xbkb3lAu6k+p+XLlSyxPjl3XXda2qp74+itSbkKU= +github.com/viant/xdatly/handler v0.0.0-20251202205015-5f121a805ed3/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 h1:G+e1MMDxQXUPPlAXVNlRqSLTLra7udGQZUu3hnr0Y8M= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52/go.mod h1:LJN2m8xJjtYNCvyvNrVanJwvzj8+hYCuPswL8H4qRG0= github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a h1:jecH7mH63gj1zJwD18SdvSHM9Ttr9FEOnhHkYfkCNkI= diff --git a/repository/logging/logging.go b/repository/logging/logging.go index 5dc76e96b..0f28a6284 100644 --- a/repository/logging/logging.go +++ b/repository/logging/logging.go @@ -3,6 +3,8 @@ package logging import ( "encoding/json" "fmt" + "reflect" + "runtime/debug" "strconv" "time" @@ -51,7 +53,10 @@ func Log(config *Config, execContext *exec.Context) { func safeMarshal(label string, v any) []byte { defer func() { if r := recover(); r != nil { - fmt.Printf("[LOG-MARSHAL-PANIC] label=%s type=%T panic=%v\n", label, v, r) + fmt.Printf("[LOG-MARSHAL-PANIC] label=%s type=%T panic=%v\nSTACK:\n%s\n", label, v, r, debug.Stack()) + if execCtx, ok := v.(*exec.Context); ok { + findBadField(execCtx) + } } }() data, err := json.Marshal(v) @@ -61,3 +66,29 @@ func safeMarshal(label string, v any) []byte { } return data } + +func findBadField(execCtx *exec.Context) { + val := reflect.ValueOf(execCtx).Elem() + typ := val.Type() + for i := 0; i < val.NumField(); i++ { + field := val.Field(i) + fieldType := typ.Field(i) + fieldName := fieldType.Name + + // Skip unexported fields + if !field.CanInterface() { + continue + } + + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf("[BAD-FIELD-PANIC] %s (%s): %v\n", fieldName, field.Type(), r) + } + }() + if _, err := json.Marshal(field.Interface()); err != nil { + fmt.Printf("[BAD-FIELD-ERROR] %s (%s): %v\n", fieldName, field.Type(), err) + } + }() + } +} diff --git a/service/executor/service.go b/service/executor/service.go index 01df6c631..086a40695 100644 --- a/service/executor/service.go +++ b/service/executor/service.go @@ -220,7 +220,7 @@ func (e *Executor) logMetrics(ctx context.Context, table string, operation strin if err != nil { metric.Error = err.Error() } - value.(*exec.Context).Metrics.Append(&metric) + value.(*exec.Context).AppendMetrics(&metric) } func (e *Executor) handleInsert(ctx context.Context, sess *dbSession, executable *expand2.Executable, db *sql.DB) error { diff --git a/service/reader/service.go b/service/reader/service.go index d3701f9bc..1fda9fc9e 100644 --- a/service/reader/service.go +++ b/service/reader/service.go @@ -104,7 +104,7 @@ func (s *Service) afterRead(ctx context.Context, aSession *Session, collector *v onFinish(end) if value := ctx.Value(exec.ContextKey); value != nil { if exeCtx := value.(*exec.Context); exeCtx != nil { - exeCtx.Metrics.Append(metrics) + exeCtx.AppendMetrics(metrics) } } } From 5236e65df147a5117615f7d5e3be37d950d6912c Mon Sep 17 00:00:00 2001 From: Himanshu Shishir Shah Date: Tue, 2 Dec 2025 16:26:20 -0800 Subject: [PATCH 088/117] ENG-52439: adding unit test cases --- repository/logging/logging_test.go | 194 +++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 repository/logging/logging_test.go diff --git a/repository/logging/logging_test.go b/repository/logging/logging_test.go new file mode 100644 index 000000000..a9beb4293 --- /dev/null +++ b/repository/logging/logging_test.go @@ -0,0 +1,194 @@ +package logging + +import ( + "bytes" + "encoding/json" + "io" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/viant/xdatly/handler/exec" +) + +// TestSafeMarshal_Success tests successful JSON marshaling +func TestSafeMarshal_Success(t *testing.T) { + type TestStruct struct { + Name string `json:"name"` + Value int `json:"value"` + } + + testData := TestStruct{ + Name: "test", + Value: 42, + } + + result := safeMarshal("TEST", testData) + assert.NotNil(t, result, "safeMarshal should return non-nil for valid data") + + var unmarshaled TestStruct + err := json.Unmarshal(result, &unmarshaled) + assert.NoError(t, err) + assert.Equal(t, testData, unmarshaled) +} + +// TestSafeMarshal_Error tests safeMarshal with a value that causes a marshaling error +func TestSafeMarshal_Error(t *testing.T) { + // Channel cannot be marshaled to JSON + ch := make(chan int) + result := safeMarshal("TEST", ch) + assert.Nil(t, result, "safeMarshal should return nil when marshaling fails") +} + +// TestSafeMarshal_Panic tests safeMarshal with a value that causes a panic +func TestSafeMarshal_Panic(t *testing.T) { + // Function cannot be marshaled and may cause panic + fn := func() {} + result := safeMarshal("TEST", fn) + assert.Nil(t, result, "safeMarshal should return nil when marshaling panics") +} + +// TestSafeMarshal_ExecContext tests safeMarshal with exec.Context +func TestSafeMarshal_ExecContext(t *testing.T) { + execCtx := exec.NewContext("GET", "/test", nil, "") + result := safeMarshal("EXECCONTEXT", execCtx) + + // Should either succeed (return non-nil) or fail gracefully (return nil) + // The important thing is it doesn't panic + if result != nil { + assert.NotEmpty(t, result) + } +} + +// TestSafeMarshal_NilValue tests safeMarshal with nil value +func TestSafeMarshal_NilValue(t *testing.T) { + result := safeMarshal("TEST", nil) + assert.NotNil(t, result) + assert.Equal(t, []byte("null"), result) +} + +// TestFindBadField_ValidExecContext tests findBadField with a valid exec.Context +func TestFindBadField_ValidExecContext(t *testing.T) { + // Capture stdout to check output + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + execCtx := exec.NewContext("GET", "/test", nil, "") + findBadField(execCtx) + + // Close write pipe and restore stdout + w.Close() + os.Stdout = oldStdout + + // Read captured output + var buf bytes.Buffer + io.Copy(&buf, r) + output := buf.String() + + // With a valid exec.Context, there should be no bad field errors + assert.NotContains(t, output, "[BAD-FIELD-ERROR]", "valid exec.Context should not have bad fields") + assert.NotContains(t, output, "[BAD-FIELD-PANIC]", "valid exec.Context should not panic on field marshaling") +} + +// TestFindBadField_CompletesWithoutPanic tests that findBadField completes without panicking +func TestFindBadField_CompletesWithoutPanic(t *testing.T) { + execCtx := exec.NewContext("GET", "/test", nil, "") + + // Should complete without panicking + assert.NotPanics(t, func() { + findBadField(execCtx) + }) +} + +// TestSafeMarshal_WithLabel tests that safeMarshal uses the label parameter in error messages +func TestSafeMarshal_WithLabel(t *testing.T) { + // Capture stdout to verify label is used in error messages + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + // Use a value that will cause an error + ch := make(chan int) + result := safeMarshal("CUSTOM_LABEL", ch) + + // Close write pipe and restore stdout + w.Close() + os.Stdout = oldStdout + + // Read captured output + var buf bytes.Buffer + io.Copy(&buf, r) + output := buf.String() + + assert.Nil(t, result, "should return nil on error") + if strings.Contains(output, "[LOG-MARSHAL-ERROR]") { + assert.Contains(t, output, "CUSTOM_LABEL", "error message should include the label") + } +} + +// TestSafeMarshal_RecoversFromPanic tests that safeMarshal properly recovers from panics +func TestSafeMarshal_RecoversFromPanic(t *testing.T) { + // Capture stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + // Create a type that will panic during JSON marshaling + type PanicType struct { + Value func() // Functions cannot be marshaled + } + + panicValue := PanicType{ + Value: func() {}, + } + + // This should not cause the test to panic + result := safeMarshal("PANIC_TEST", panicValue) + + // Close write pipe and restore stdout + w.Close() + os.Stdout = oldStdout + + // Read captured output + var buf bytes.Buffer + io.Copy(&buf, r) + output := buf.String() + + // Function should recover and return nil + assert.Nil(t, result, "should return nil after recovering from panic") + // Should log the panic + if strings.Contains(output, "[LOG-MARSHAL-PANIC]") { + assert.Contains(t, output, "PANIC_TEST", "panic log should include label") + } +} + +// TestSafeMarshal_ExecContextPanicCallsFindBadField tests that safeMarshal calls findBadField when exec.Context panics +func TestSafeMarshal_ExecContextPanicCallsFindBadField(t *testing.T) { + // Capture stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + execCtx := exec.NewContext("GET", "/test", nil, "") + + // Try to marshal - if it panics, findBadField should be called + result := safeMarshal("EXECCONTEXT", execCtx) + + // Close write pipe and restore stdout + w.Close() + os.Stdout = oldStdout + + // Read captured output + var buf bytes.Buffer + io.Copy(&buf, r) + output := buf.String() + + // If marshaling panicked, findBadField should have been called + if result == nil && strings.Contains(output, "[LOG-MARSHAL-PANIC]") { + // findBadField should have been called (though output may be empty if no bad fields found) + // The important thing is that the function didn't crash + assert.True(t, true, "findBadField should be called when exec.Context panics") + } +} From ee5d315ca6c48e0b27a712fde94f3f17a7909a01 Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 3 Dec 2025 16:51:12 -0800 Subject: [PATCH 089/117] patched type pointers --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b34d19359..c3df8efd4 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/viant/pgo v0.11.0 github.com/viant/scy v0.24.0 github.com/viant/sqlx v0.17.8 - github.com/viant/structql v0.5.3 + github.com/viant/structql v0.5.4 github.com/viant/toolbox v0.37.0 github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 github.com/viant/xreflect v0.7.3 diff --git a/go.sum b/go.sum index ea4bdaa33..17a444947 100644 --- a/go.sum +++ b/go.sum @@ -1146,6 +1146,8 @@ github.com/viant/structology v0.8.0 h1:WKdK67l+O1eqsubn8PWMhWcgspUGJ22SgJxUMfiRg github.com/viant/structology v0.8.0/go.mod h1:Fnm1DyR4gfyPbnhBMkQB5lR6/isYDnncBFO1nCxxmqs= github.com/viant/structql v0.5.3 h1:QeOxvF0so8VFGt5bm+Jr6FL8uRnXkvwWY+ZCkbe3zsI= github.com/viant/structql v0.5.3/go.mod h1:nm9AYnAuSKH7b7pG+dKVxbQrr1Mgp1CQEMvUwwkE+I8= +github.com/viant/structql v0.5.4 h1:bMdcOpzU8UMoe5OBcyJVRxLAndvU1oj3ysvPUgBckCI= +github.com/viant/structql v0.5.4/go.mod h1:nm9AYnAuSKH7b7pG+dKVxbQrr1Mgp1CQEMvUwwkE+I8= github.com/viant/tagly v0.3.0 h1:Y8IckveeSrroR8yisq4MBdxhcNqf4v8II01uCpamh4E= github.com/viant/tagly v0.3.0/go.mod h1:PauQQkHmAvL5lFGr4gIgi+PE0aUPggBIBYN34sX2Oes= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= From 010a92a96e0452b4e3d339a829feaafc64259afd Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 4 Dec 2025 15:14:52 -0800 Subject: [PATCH 090/117] patched type pointers --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index bbb047798..4e6b4afed 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/viant/parsly v0.3.3 github.com/viant/pgo v0.11.0 github.com/viant/scy v0.24.0 - github.com/viant/sqlx v0.17.8 + github.com/viant/sqlx v0.21.0 github.com/viant/structql v0.5.4 github.com/viant/toolbox v0.37.0 github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 diff --git a/go.sum b/go.sum index eaf67828d..7a75b3fc5 100644 --- a/go.sum +++ b/go.sum @@ -1140,6 +1140,8 @@ github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= github.com/viant/sqlx v0.17.8 h1:YxGTrXC2B1JmDz1qp8G+G9hGPk7XCRevWN1E4E+ZlCI= github.com/viant/sqlx v0.17.8/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= +github.com/viant/sqlx v0.21.0 h1:Lx5KXmzfSjSvZZX5P0Ua9kFGvAmCxAjLOPe9pQA7VmY= +github.com/viant/sqlx v0.21.0/go.mod h1:woTOwNiqvt6SqkI+5nyzlixcRTTV0IvLZUTberqb8mo= github.com/viant/structology v0.8.0 h1:WKdK67l+O1eqsubn8PWMhWcgspUGJ22SgJxUMfiRgqE= github.com/viant/structology v0.8.0/go.mod h1:Fnm1DyR4gfyPbnhBMkQB5lR6/isYDnncBFO1nCxxmqs= github.com/viant/structql v0.5.3 h1:QeOxvF0so8VFGt5bm+Jr6FL8uRnXkvwWY+ZCkbe3zsI= From 0b0e8b63619f706c726e7f81b59d8548cb75bdf9 Mon Sep 17 00:00:00 2001 From: Himanshu Shishir Shah Date: Thu, 4 Dec 2025 17:46:37 -0800 Subject: [PATCH 091/117] ENG-52379: adding trace id to info logs --- shared/logging/logger.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/shared/logging/logger.go b/shared/logging/logger.go index aea30470f..9c208eb42 100644 --- a/shared/logging/logger.go +++ b/shared/logging/logger.go @@ -4,14 +4,16 @@ import ( "context" "encoding/json" "fmt" - "github.com/aws/aws-lambda-go/events" - "github.com/viant/xdatly/handler/logger" "io" "log/slog" "os" regexp "regexp" "runtime" strings "strings" + + "github.com/aws/aws-lambda-go/events" + "github.com/viant/xdatly/handler/exec" + "github.com/viant/xdatly/handler/logger" ) const ( @@ -122,6 +124,15 @@ func (s *slogger) getContextValues(ctx context.Context) []any { if openTelemetryTraceId != nil { values = append(values, "OpenTelemetryTraceId", openTelemetryTraceId) } + + execContext := ctx.Value(exec.ContextKey) + if execContext != nil { + c, ok := execContext.(*exec.Context) + if ok && c != nil && c.Trace != nil { + values = append(values, "reqTraceId", c.Trace.TraceID) + } + } + return values } From 7f60767d0ee9f0acbfbc7879c2b1f60cf308d190 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 8 Dec 2025 13:32:13 -0800 Subject: [PATCH 092/117] patched type pointers --- .../function/allowedorderbycolumn.go | 56 +++++++++++++++++++ internal/translator/function/init.go | 1 + internal/translator/function/orderby.go | 1 + internal/translator/view.go | 4 +- service/session/selector.go | 3 + view/config.go | 14 ++++- view/view.go | 19 ++++--- 7 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 internal/translator/function/allowedorderbycolumn.go diff --git a/internal/translator/function/allowedorderbycolumn.go b/internal/translator/function/allowedorderbycolumn.go new file mode 100644 index 000000000..40de57f5b --- /dev/null +++ b/internal/translator/function/allowedorderbycolumn.go @@ -0,0 +1,56 @@ +package function + +import ( + "fmt" + "strings" + + "github.com/viant/datly/view" + "github.com/viant/sqlparser" +) + +type allowedOrderByColumns struct{} + +func (c *allowedOrderByColumns) Apply(args []string, column *sqlparser.Column, resource *view.Resource, aView *view.View) error { + if aView.Selector == nil { + aView.Selector = &view.Config{} + } + values, err := convertArguments(c, args) + if err != nil { + return err + } + if aView.Selector.Constraints == nil { + aView.Selector.Constraints = &view.Constraints{} + } + aView.Selector.Constraints.OrderBy = true + if len(values) == 0 { + return fmt.Errorf("failed to discover column in allowedOrderByColumns") + } + columns, ok := values[0].(string) + if !ok { + return fmt.Errorf("invalid columns type: %T, expected: %T in allowedOrderByColumns", values[0], columns) + } + for _, column := range strings.Split(columns, ",") { + column = strings.TrimSpace(column) + aView.Selector.Constraints.OrderByColumn = append(aView.Selector.Constraints.OrderByColumn, column) + } + return nil +} + +func (c *allowedOrderByColumns) Name() string { + return "allowed_order_by_columns" +} + +func (c *allowedOrderByColumns) Description() string { + return "set view.Selector.OrderBy and enables corresponding view.Selector.Constraints.OrderBy" +} + +func (c *allowedOrderByColumns) Arguments() []*Argument { + return []*Argument{ + { + Name: "allowedOrderByColumns", + Description: "query selector allowedOrderByColumns", + Required: true, + DataType: "string", + }, + } +} diff --git a/internal/translator/function/init.go b/internal/translator/function/init.go index b67d258f0..b0141c3d8 100644 --- a/internal/translator/function/init.go +++ b/internal/translator/function/init.go @@ -5,6 +5,7 @@ func init() { _registry.Register(&cache{}) _registry.Register(&limit{}) _registry.Register(&orderBy{}) + _registry.Register(&allowedOrderByColumns{}) _registry.Register(&cardinality{}) _registry.Register(&allownulls{}) _registry.Register(&matchStrategy{}) diff --git a/internal/translator/function/orderby.go b/internal/translator/function/orderby.go index 645be6058..9dc22f5ca 100644 --- a/internal/translator/function/orderby.go +++ b/internal/translator/function/orderby.go @@ -20,6 +20,7 @@ func (c *orderBy) Apply(args []string, column *sqlparser.Column, resource *view. } aView.Selector.Constraints.OrderBy = true aView.Selector.OrderBy = values[0].(string) + return nil } diff --git a/internal/translator/view.go b/internal/translator/view.go index ab94c500e..f8caa7157 100644 --- a/internal/translator/view.go +++ b/internal/translator/view.go @@ -2,15 +2,17 @@ package translator import ( "fmt" + "github.com/viant/datly/internal/asset" "github.com/viant/datly/internal/inference" "github.com/viant/datly/internal/setter" "github.com/viant/datly/internal/translator/parser" + "path" + "github.com/viant/datly/view" "github.com/viant/datly/view/state" "github.com/viant/tagly/format/text" - "path" ) type ( diff --git a/service/session/selector.go b/service/session/selector.go index 467f26003..b6ff7c140 100644 --- a/service/session/selector.go +++ b/service/session/selector.go @@ -162,6 +162,9 @@ func (s *Session) setOrderByQuerySelector(value interface{}, ns *view.NamespaceV continue //position based, not need to validate } + if ns.View.Selector.Constraints.HasOrderByColumn(column) { + continue + } _, ok := ns.View.ColumnByName(column) if !ok { return fmt.Errorf("not found column %v at view %v", items, ns.View.Name) diff --git a/view/config.go b/view/config.go index 485fe5f45..8605e86f3 100644 --- a/view/config.go +++ b/view/config.go @@ -3,12 +3,13 @@ package view import ( "context" "fmt" + "reflect" + "strings" + "github.com/viant/datly/shared" "github.com/viant/datly/view/state" "github.com/viant/xdatly/codec" "github.com/viant/xreflect" - "reflect" - "strings" ) const ( @@ -90,6 +91,15 @@ func (c *Config) GetContentFormatParameter() *state.Parameter { return QueryStateParameters.ContentFormatParameter } +func (c *Constraints) HasOrderByColumn(name string) bool { + for _, candidate := range c.OrderByColumn { + if candidate == name { + return true + } + } + return false +} + func (c *Config) Init(ctx context.Context, resource *Resource, parent *View) error { if err := c.ensureConstraints(resource); err != nil { return err diff --git a/view/view.go b/view/view.go index d2f3bf567..a482cfa12 100644 --- a/view/view.go +++ b/view/view.go @@ -155,15 +155,16 @@ func (v *View) Context(ctx context.Context) context.Context { // Constraints configure what can be selected by Statelet // For each _field, default value is `false` type Constraints struct { - Criteria bool - OrderBy bool - Limit bool - Offset bool - Projection bool //enables columns projection from client (default ${NS}_fields= query param) - Filterable []string - SQLMethods []*Method `json:",omitempty"` - _sqlMethods map[string]*Method - Page *bool + Criteria bool + OrderBy bool + OrderByColumn []string + Limit bool + Offset bool + Projection bool //enables columns projection from client (default ${NS}_fields= query param) + Filterable []string + SQLMethods []*Method `json:",omitempty"` + _sqlMethods map[string]*Method + Page *bool } func (v *View) Resource() state.Resource { From 72023c4ad6f5e0f832118a18d2f13e55acb87884 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 8 Dec 2025 13:43:26 -0800 Subject: [PATCH 093/117] patched type pointers --- service/reader/sql.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/service/reader/sql.go b/service/reader/sql.go index bcb7aff93..d1f4e54b9 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -341,7 +341,7 @@ func (b *Builder) updateColumnsIn(params *view.CriteriaParam, batchData *view.Ba params.ColumnsIn = sb.String() } -func (b *Builder) appendOrderBy(sb *strings.Builder, view *view.View, selector *view.Statelet) error { +func (b *Builder) appendOrderBy(sb *strings.Builder, aView *view.View, selector *view.Statelet) error { if selector.OrderBy != "" { fragment := strings.Builder{} items := strings.Split(strings.ReplaceAll(selector.OrderBy, ":", " "), ",") @@ -362,12 +362,19 @@ func (b *Builder) appendOrderBy(sb *strings.Builder, view *view.View, selector * switch strings.ToLower(sortDirection) { case "asc", "desc", "": default: - return fmt.Errorf("invalid sort direction %v for column %v at view %v", sortDirection, column, view.Name) + return fmt.Errorf("invalid sort direction %v for column %v at aView %v", sortDirection, column, aView.Name) } - col, ok := view.ColumnByName(column) + col, ok := aView.ColumnByName(column) if !ok { - return fmt.Errorf("not found column %v at view %v", column, view.Name) + if aView.Selector.Constraints.HasOrderByColumn(column) { + col = &view.Column{ + Name: column, + } + } + } + if !ok { + return fmt.Errorf("not found column %v at aView %v", column, aView.Name) } fragment.WriteString(col.Name) if sortDirection != "" { @@ -380,9 +387,9 @@ func (b *Builder) appendOrderBy(sb *strings.Builder, view *view.View, selector * return nil } - if view.Selector.OrderBy != "" { + if aView.Selector.OrderBy != "" { sb.WriteString(orderByFragment) - sb.WriteString(strings.ReplaceAll(view.Selector.OrderBy, ":", " ")) + sb.WriteString(strings.ReplaceAll(aView.Selector.OrderBy, ":", " ")) return nil } From 93a78c4bae6ec91dc7c587bb469af5bf901be332 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 8 Dec 2025 13:43:53 -0800 Subject: [PATCH 094/117] patched type pointers --- service/reader/sql.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/service/reader/sql.go b/service/reader/sql.go index d1f4e54b9..82f3821e2 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -371,7 +371,9 @@ func (b *Builder) appendOrderBy(sb *strings.Builder, aView *view.View, selector col = &view.Column{ Name: column, } + ok = true } + } if !ok { return fmt.Errorf("not found column %v at aView %v", column, aView.Name) From 80bd6bfa6b7d54bc546f1d997f50aa0120e0efe9 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 8 Dec 2025 13:50:34 -0800 Subject: [PATCH 095/117] patched type pointers --- service/reader/sql.go | 1 + view/config.go | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/service/reader/sql.go b/service/reader/sql.go index 82f3821e2..3a34827e9 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -367,6 +367,7 @@ func (b *Builder) appendOrderBy(sb *strings.Builder, aView *view.View, selector col, ok := aView.ColumnByName(column) if !ok { + if aView.Selector.Constraints.HasOrderByColumn(column) { col = &view.Column{ Name: column, diff --git a/view/config.go b/view/config.go index 8605e86f3..dad89cb15 100644 --- a/view/config.go +++ b/view/config.go @@ -92,8 +92,9 @@ func (c *Config) GetContentFormatParameter() *state.Parameter { } func (c *Constraints) HasOrderByColumn(name string) bool { + dotedName := "." + name for _, candidate := range c.OrderByColumn { - if candidate == name { + if candidate == name || strings.HasSuffix(candidate, dotedName) { return true } } From d7ee4a3cb45ff279cc3b39eb6b4dc946a93027dd Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 8 Dec 2025 13:59:31 -0800 Subject: [PATCH 096/117] patched type pointers --- .../function/allowedorderbycolumn.go | 28 ++++++++++++++++--- service/reader/sql.go | 3 +- view/config.go | 9 ++---- view/view.go | 2 +- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/internal/translator/function/allowedorderbycolumn.go b/internal/translator/function/allowedorderbycolumn.go index 40de57f5b..cfad0bbf7 100644 --- a/internal/translator/function/allowedorderbycolumn.go +++ b/internal/translator/function/allowedorderbycolumn.go @@ -23,15 +23,35 @@ func (c *allowedOrderByColumns) Apply(args []string, column *sqlparser.Column, r } aView.Selector.Constraints.OrderBy = true if len(values) == 0 { - return fmt.Errorf("failed to discover column in allowedOrderByColumns") + return fmt.Errorf("failed to discover expression in allowedOrderByColumns") } columns, ok := values[0].(string) if !ok { return fmt.Errorf("invalid columns type: %T, expected: %T in allowedOrderByColumns", values[0], columns) } - for _, column := range strings.Split(columns, ",") { - column = strings.TrimSpace(column) - aView.Selector.Constraints.OrderByColumn = append(aView.Selector.Constraints.OrderByColumn, column) + if len(aView.Selector.Constraints.OrderByColumn) == 0 { + aView.Selector.Constraints.OrderByColumn = map[string]string{} + } + for _, expression := range strings.Split(columns, ",") { + expression = strings.TrimSpace(expression) + + key := expression + value := expression + if strings.Contains(expression, ":") { + parts := strings.SplitN(expression, ":", 2) + key = parts[0] + value = parts[1] + } + + aView.Selector.Constraints.OrderByColumn[key] = value + lcKey := strings.ToLower(key) + if lcKey != key { + aView.Selector.Constraints.OrderByColumn[lcKey] = value + } + + if index := strings.Index(key, "."); index != -1 { + aView.Selector.Constraints.OrderByColumn[key[index+1:]] = value + } } return nil } diff --git a/service/reader/sql.go b/service/reader/sql.go index 3a34827e9..256cd26f3 100644 --- a/service/reader/sql.go +++ b/service/reader/sql.go @@ -369,8 +369,9 @@ func (b *Builder) appendOrderBy(sb *strings.Builder, aView *view.View, selector if !ok { if aView.Selector.Constraints.HasOrderByColumn(column) { + mapped := aView.Selector.Constraints.OrderByColumn[column] col = &view.Column{ - Name: column, + Name: mapped, } ok = true } diff --git a/view/config.go b/view/config.go index dad89cb15..5dd70f6de 100644 --- a/view/config.go +++ b/view/config.go @@ -92,13 +92,8 @@ func (c *Config) GetContentFormatParameter() *state.Parameter { } func (c *Constraints) HasOrderByColumn(name string) bool { - dotedName := "." + name - for _, candidate := range c.OrderByColumn { - if candidate == name || strings.HasSuffix(candidate, dotedName) { - return true - } - } - return false + _, ok := c.OrderByColumn[name] + return ok } func (c *Config) Init(ctx context.Context, resource *Resource, parent *View) error { diff --git a/view/view.go b/view/view.go index a482cfa12..9274c8053 100644 --- a/view/view.go +++ b/view/view.go @@ -157,7 +157,7 @@ func (v *View) Context(ctx context.Context) context.Context { type Constraints struct { Criteria bool OrderBy bool - OrderByColumn []string + OrderByColumn map[string]string Limit bool Offset bool Projection bool //enables columns projection from client (default ${NS}_fields= query param) From 0c1053eb94b64e64a8ccdb4e8d5f94d0717a7f05 Mon Sep 17 00:00:00 2001 From: Himanshu Shishir Shah Date: Tue, 9 Dec 2025 13:08:53 -0800 Subject: [PATCH 097/117] ENG-51959: using snapshot for logging --- go.mod | 2 +- go.sum | 8 ++------ repository/logging/logging.go | 35 +++++++++++++++++------------------ 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 4e6b4afed..00d915490 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,7 @@ require ( github.com/viant/tagly v0.3.0 github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 - github.com/viant/xdatly/handler v0.0.0-20251202205015-5f121a805ed3 + github.com/viant/xdatly/handler v0.0.0-20251208172928-dd34b7f09fd5 github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a github.com/viant/xlsy v0.3.1 diff --git a/go.sum b/go.sum index 7a75b3fc5..8ed5f2096 100644 --- a/go.sum +++ b/go.sum @@ -1138,14 +1138,10 @@ github.com/viant/scy v0.24.0 h1:KAC3IUARkQxTNSuwBK2YhVBJMOOLN30YaLKHbbuSkMU= github.com/viant/scy v0.24.0/go.mod h1:7uNRS67X45YN+JqTLCcMEhehffVjqrejULEDln9p0Ao= github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns= github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= -github.com/viant/sqlx v0.17.8 h1:YxGTrXC2B1JmDz1qp8G+G9hGPk7XCRevWN1E4E+ZlCI= -github.com/viant/sqlx v0.17.8/go.mod h1:dizufL+nTNqDCpivUnE2HqtddTp2TdA6WFghGfZo11c= github.com/viant/sqlx v0.21.0 h1:Lx5KXmzfSjSvZZX5P0Ua9kFGvAmCxAjLOPe9pQA7VmY= github.com/viant/sqlx v0.21.0/go.mod h1:woTOwNiqvt6SqkI+5nyzlixcRTTV0IvLZUTberqb8mo= github.com/viant/structology v0.8.0 h1:WKdK67l+O1eqsubn8PWMhWcgspUGJ22SgJxUMfiRgqE= github.com/viant/structology v0.8.0/go.mod h1:Fnm1DyR4gfyPbnhBMkQB5lR6/isYDnncBFO1nCxxmqs= -github.com/viant/structql v0.5.3 h1:QeOxvF0so8VFGt5bm+Jr6FL8uRnXkvwWY+ZCkbe3zsI= -github.com/viant/structql v0.5.3/go.mod h1:nm9AYnAuSKH7b7pG+dKVxbQrr1Mgp1CQEMvUwwkE+I8= github.com/viant/structql v0.5.4 h1:bMdcOpzU8UMoe5OBcyJVRxLAndvU1oj3ysvPUgBckCI= github.com/viant/structql v0.5.4/go.mod h1:nm9AYnAuSKH7b7pG+dKVxbQrr1Mgp1CQEMvUwwkE+I8= github.com/viant/tagly v0.3.0 h1:Y8IckveeSrroR8yisq4MBdxhcNqf4v8II01uCpamh4E= @@ -1162,8 +1158,8 @@ github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a h1:7CLO2LjVnFgOwN0F github.com/viant/xdatly v0.5.4-0.20251113181159-0ac8b8b0ff3a/go.mod h1:lZKZHhVdCZ3U9TU6GUFxKoGN3dPtqt2HkDYzJPq5CEs= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259 h1:9Yry3PUBDzc4rWacOYvAq/TKrTV0agvMF0gwm2gaoHI= github.com/viant/xdatly/extension v0.0.0-20231013204918-ecf3c2edf259/go.mod h1:fb8YgbVadk8X5ZLz49LWGzWmQlZd7Y/I5wE0ru44bIo= -github.com/viant/xdatly/handler v0.0.0-20251202205015-5f121a805ed3 h1:Xw0xbkb3lAu6k+p+XLlSyxPjl3XXda2qp74+itSbkKU= -github.com/viant/xdatly/handler v0.0.0-20251202205015-5f121a805ed3/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= +github.com/viant/xdatly/handler v0.0.0-20251208172928-dd34b7f09fd5 h1:CrT0HTlQul8FoGN0peylVczAOUEXKVqRAiB35ypRNHY= +github.com/viant/xdatly/handler v0.0.0-20251208172928-dd34b7f09fd5/go.mod h1:OeV4sVatklNs31nFnZtSp7lEvKJRoVJbH5opNRmRPg0= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52 h1:G+e1MMDxQXUPPlAXVNlRqSLTLra7udGQZUu3hnr0Y8M= github.com/viant/xdatly/types/core v0.0.0-20250307183722-8c84fc717b52/go.mod h1:LJN2m8xJjtYNCvyvNrVanJwvzj8+hYCuPswL8H4qRG0= github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a h1:jecH7mH63gj1zJwD18SdvSHM9Ttr9FEOnhHkYfkCNkI= diff --git a/repository/logging/logging.go b/repository/logging/logging.go index 0f28a6284..b618199ac 100644 --- a/repository/logging/logging.go +++ b/repository/logging/logging.go @@ -6,44 +6,43 @@ import ( "reflect" "runtime/debug" "strconv" - "time" "github.com/viant/xdatly/handler/exec" ) func Log(config *Config, execContext *exec.Context) { - execContext.ElapsedMs = int(time.Since(execContext.StartTime).Milliseconds()) + snap := execContext.SnapshotForLogging() includeSQL := config.ShallIncludeSQL() if !includeSQL { - execContext.Metrics = execContext.Metrics.HideMetrics() + snap.Metrics = snap.Metrics.HideMetrics() } if config.IsAuditEnabled() { - data := safeMarshal("EXECCONTEXT", execContext) + data := safeMarshal("EXECCONTEXT", snap) fmt.Println("[AUDIT]", string(data)) } if config.IsTracingEnabled() { - trace := execContext.Trace + trace := snap.Trace rootSpan := trace.Spans[0] - spans := execContext.Metrics.ToSpans(&rootSpan.SpanID) - if execContext.Auth != nil { - if execContext.Auth.UserID != 0 { - rootSpan.Attributes["jwt.uid"] = strconv.Itoa(execContext.Auth.UserID) + spans := snap.Metrics.ToSpans(&rootSpan.SpanID) + if snap.Auth != nil { + if snap.Auth.UserID != 0 { + rootSpan.Attributes["jwt.uid"] = strconv.Itoa(snap.Auth.UserID) } - if execContext.Auth.Username != "" { - rootSpan.Attributes["jwt.username"] = execContext.Auth.Username + if snap.Auth.Username != "" { + rootSpan.Attributes["jwt.username"] = snap.Auth.Username } - if execContext.Auth.Email != "" { - rootSpan.Attributes["jwt.email"] = execContext.Auth.Email + if snap.Auth.Email != "" { + rootSpan.Attributes["jwt.email"] = snap.Auth.Email } - if execContext.Auth.Scope != "" { - rootSpan.Attributes["jwt.scope"] = execContext.Auth.Scope + if snap.Auth.Scope != "" { + rootSpan.Attributes["jwt.scope"] = snap.Auth.Scope } } trace.Append(spans...) - if execContext.Error != "" { - trace.Spans[0].SetStatus(fmt.Errorf(execContext.Error)) + if snap.Error != "" { + trace.Spans[0].SetStatus(fmt.Errorf(snap.Error)) } else { - trace.Spans[0].SetStatusFromHTTPCode(execContext.StatusCode) + trace.Spans[0].SetStatusFromHTTPCode(snap.StatusCode) } traceData := safeMarshal("TRACE", trace) fmt.Println("[TRACE]", string(traceData)) From f6ac4312e6181b940e1236567d650672580a747d Mon Sep 17 00:00:00 2001 From: Himanshu Shishir Shah Date: Tue, 9 Dec 2025 16:48:54 -0800 Subject: [PATCH 098/117] ENG-52379: updating logic to add trace id to logs --- shared/logging/logger.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/shared/logging/logger.go b/shared/logging/logger.go index 9c208eb42..fe98d85ae 100644 --- a/shared/logging/logger.go +++ b/shared/logging/logger.go @@ -125,12 +125,19 @@ func (s *slogger) getContextValues(ctx context.Context) []any { values = append(values, "OpenTelemetryTraceId", openTelemetryTraceId) } - execContext := ctx.Value(exec.ContextKey) + execContext := exec.GetContext(ctx) if execContext != nil { - c, ok := execContext.(*exec.Context) - if ok && c != nil && c.Trace != nil { - values = append(values, "reqTraceId", c.Trace.TraceID) + traceId := "unknown" + + // ideally TraceID and Trace.TraceID should be the same + // but xdatly/handler/exec.(*Context).setHeader TraceID first + // with the value of adp-request-id header + if execContext.TraceID != "" { + traceId = execContext.TraceID + } else if execContext.Trace != nil { + traceId = execContext.Trace.TraceID } + values = append(values, "reqTraceId", traceId) } return values From d8c4b10e61052851a0db05a394d95b06262dc3b8 Mon Sep 17 00:00:00 2001 From: Himanshu Shishir Shah Date: Wed, 10 Dec 2025 12:30:07 -0800 Subject: [PATCH 099/117] ENG-52379: making the trace id key configurable --- shared/logging/logger.go | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/shared/logging/logger.go b/shared/logging/logger.go index fe98d85ae..de26bc87d 100644 --- a/shared/logging/logger.go +++ b/shared/logging/logger.go @@ -24,18 +24,28 @@ const ( WARN = "WARN" ERROR = "ERROR" UNKNOWN = "UNKNOWN" // Indicate other environment + DefaultTraceIdKey = "reqTraceId" ) type slogger struct { - logger *slog.Logger - level slog.Level + logger *slog.Logger + level slog.Level + traceIdKey string +} + +type Option func(l *slogger) + +func WithTraceIdKey(key string) Option { + return func(l *slogger) { + l.traceIdKey = key + } } // Init creates an ISLogger instance, a structured logger using the JSON Handler. // Creating this logger sets this as the default logger, so any logging after this // which goes through the standard logging package will also produce JSON structured // logs. -func New(level string, dest io.Writer) logger.Logger { +func New(level string, dest io.Writer, opts ...Option) logger.Logger { if dest == nil { dest = os.Stdout } @@ -63,9 +73,12 @@ func New(level string, dest io.Writer) logger.Logger { }) sl := slog.New(handler) slog.SetDefault(sl) - logger := &slogger{sl, logLevel} + l := &slogger{sl, logLevel, DefaultTraceIdKey} + for _, opt := range opts { + opt(l) + } - return logger + return l } func (s *slogger) IsDebugEnabled() bool { @@ -130,14 +143,14 @@ func (s *slogger) getContextValues(ctx context.Context) []any { traceId := "unknown" // ideally TraceID and Trace.TraceID should be the same - // but xdatly/handler/exec.(*Context).setHeader TraceID first - // with the value of adp-request-id header + // but xdatly/handler/exec.(*Context).setHeader sets TraceID first + // with the value of XDATLY_TRACING_HEADER env var value header (adp-request-id for datly platform) if execContext.TraceID != "" { traceId = execContext.TraceID } else if execContext.Trace != nil { traceId = execContext.Trace.TraceID } - values = append(values, "reqTraceId", traceId) + values = append(values, s.traceIdKey, traceId) } return values From 14e6a88bd0061ff3a66acbd36ddf4414043e65a7 Mon Sep 17 00:00:00 2001 From: adranwit Date: Sun, 14 Dec 2025 07:26:14 -0800 Subject: [PATCH 100/117] patched type pointers --- internal/translator/service.go | 7 ++++++- internal/translator/view.go | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/translator/service.go b/internal/translator/service.go index 539ceade9..206762d1b 100644 --- a/internal/translator/service.go +++ b/internal/translator/service.go @@ -489,7 +489,12 @@ func (s *Service) adjustView(viewlet *Viewlet, resource *Resource, mode view.Mod if len(resource.Declarations.QuerySelectors) > 0 { for key, state := range resource.Declarations.QuerySelectors { - return fmt.Errorf("unknown query selector view %v, %v", key, state[0].Name) + switch strings.ToLower(state[0].In.Name) { + case "limit", "page", "offset", "fields", "orderby", "criteria": + default: + return fmt.Errorf("unknown query selector view %v, %v", key, state[0].In.Name) + + } } } diff --git a/internal/translator/view.go b/internal/translator/view.go index f8caa7157..fc0096ca8 100644 --- a/internal/translator/view.go +++ b/internal/translator/view.go @@ -214,7 +214,8 @@ func (v *View) buildSelector(namespace *Viewlet, rule *Rule) { selector.PageParameter = ¶meter.Parameter selector.Constraints.Page = &enabled } - delete(namespace.Resource.Declarations.QuerySelectors, namespace.Name) + + //delete(namespace.Resource.Declarations.QuerySelectors, namespace.Name) } } From 147384b169ef225a6c53cb29e133ca26b507b752 Mon Sep 17 00:00:00 2001 From: ppoudyal Date: Mon, 15 Dec 2025 12:04:41 -0500 Subject: [PATCH 101/117] added viewSyncFlag to control sync request from mcp handler. --- gateway/mcp.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/gateway/mcp.go b/gateway/mcp.go index 0a9624afe..e9687e45a 100644 --- a/gateway/mcp.go +++ b/gateway/mcp.go @@ -99,13 +99,16 @@ func (r *Router) mcpToolCallHandler(component *repository.Component, aRoute *Rou return nil, rpcErr } r.addAuthTokenIfPresent(ctx, httpReq) + + // NEW: map MCP view sync flag argument to Sync-Read header + r.addSyncReadHeaderIfPresent(ctx, component, ¶ms, httpReq) + httpReq.RequestURI = httpReq.URL.RequestURI() if uri != aRoute.URI() { if matched, _ := r.match(component.Method, uri, httpReq); matched != nil { aRoute = matched } } - rw := proxy.NewWriter() aRoute.Handle(rw, httpReq) @@ -114,6 +117,69 @@ func (r *Router) mcpToolCallHandler(component *repository.Component, aRoute *Rou } } +func (r *Router) addSyncReadHeaderIfPresent( + ctx context.Context, + component *repository.Component, + params *schema.CallToolRequestParams, + httpRequest *http.Request, +) { + if params == nil || params.Arguments == nil { + return + } + // MCP tool arguments are generated using exported Go field names, so + // the Datly view sync flag (view.SyncFlag == "viewSyncFlag") will appear + // as "viewSyncFlag" in the schema/tool call. + const mcpSyncFlagArg = "viewSyncFlag" + const headerName = "Sync-Read" + + value, ok := params.Arguments[mcpSyncFlagArg] + if !ok { + return + } + + if !isTruthy(value) { + return + } + + // Optionally, ensure that the underlying component actually declares + // a sync flag parameter; if it does not, we simply skip setting the header. + if !hasSyncFlagParameter(component) { + return + } + + httpRequest.Header.Set(headerName, "true") +} + +// hasSyncFlagParameter checks whether the component declares a selector +// sync flag parameter, which should be exposed as view.SyncFlag. +func hasSyncFlagParameter(component *repository.Component) bool { + if component == nil || component.View == nil || component.View.Selector == nil { + return false + } + param := component.View.Selector.GetSyncFlagParameter() + if param == nil { + return false + } + // The selector sync flag parameter is defined in view.Config using + // view.SyncFlag as the state key, but here we simply check that it exists. + return true +} + +// isTruthy interprets common JSON-serialised truthy values. +func isTruthy(v interface{}) bool { + switch value := v.(type) { + case bool: + return value + case string: + s := strings.TrimSpace(strings.ToLower(value)) + return s == "true" || s == "1" || s == "yes" || s == "y" + case float64: + return value != 0 + default: + return false + } +} + // collectToolParameters aggregates component input parameters with selector pagination (limit/offset) when available. func (r *Router) collectToolParameters(component *repository.Component) []*state.Parameter { var all []*state.Parameter From fea9e58d24525cee99620cfe9bb9f8bf6369c24d Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 15 Dec 2025 10:44:26 -0800 Subject: [PATCH 102/117] patched type pointers --- internal/translator/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/translator/service.go b/internal/translator/service.go index 206762d1b..f446521a3 100644 --- a/internal/translator/service.go +++ b/internal/translator/service.go @@ -489,7 +489,7 @@ func (s *Service) adjustView(viewlet *Viewlet, resource *Resource, mode view.Mod if len(resource.Declarations.QuerySelectors) > 0 { for key, state := range resource.Declarations.QuerySelectors { - switch strings.ToLower(state[0].In.Name) { + switch strings.ToLower(state[0].Name) { case "limit", "page", "offset", "fields", "orderby", "criteria": default: return fmt.Errorf("unknown query selector view %v, %v", key, state[0].In.Name) From 3ad960f62adac18a06d4dd572be1bcc594004464 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 15 Dec 2025 15:54:32 -0800 Subject: [PATCH 103/117] error reclassification --- gateway/router/status/error.go | 35 ++++++++++++++++++++++++++-------- repository/resource/service.go | 7 ++++--- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/gateway/router/status/error.go b/gateway/router/status/error.go index 3d9111abc..876dde080 100644 --- a/gateway/router/status/error.go +++ b/gateway/router/status/error.go @@ -1,6 +1,8 @@ package status import ( + "net/http" + "github.com/viant/datly/service/executor/expand" "github.com/viant/datly/utils/httputils" "github.com/viant/datly/utils/types" @@ -13,31 +15,48 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { violations := httputils.Violations{} switch actual := err.(type) { case *response.Error: - return actual.StatusCode(), actual.Message, nil + code := actual.StatusCode() + if code == 0 { + code = http.StatusInternalServerError + } + // For explicit 4xx we trust the message, for 5xx we keep it generic. + if code >= http.StatusInternalServerError { + return code, http.StatusText(http.StatusInternalServerError), nil + } + return code, actual.Message, nil case *svalidator.Validation: ret := violations.MergeSqlViolation(actual.Violations) - return statusCode, err.Error(), ret + return http.StatusBadRequest, err.Error(), ret case *govalidator.Validation: ret := violations.MergeGoViolation(actual.Violations) - return statusCode, actual.Error(), ret + return http.StatusBadRequest, actual.Error(), ret case *response.Errors: - actual.SetStatusCode(statusCode) + // Treat aggregated errors as validation-like by default. + actual.SetStatusCode(http.StatusBadRequest) for _, anError := range actual.Errors { isObj := types.IsObject(anError.Err) if isObj { - statusCode, anError.Message, anError.Object = NormalizeErr(anError.Err, statusCode) + statusCode, anError.Message, anError.Object = NormalizeErr(anError.Err, http.StatusBadRequest) } else { - statusCode, anError.Message, anError.Object = NormalizeErr(anError.Err, statusCode) + statusCode, anError.Message, anError.Object = NormalizeErr(anError.Err, http.StatusBadRequest) + } + if statusCode > actual.StatusCode() { + actual.SetStatusCode(statusCode) } } - actual.SetStatusCode(statusCode) return actual.StatusCode(), actual.Message, actual.Errors case *expand.ErrorResponse: if actual.StatusCode != 0 { statusCode = actual.StatusCode } + // If no status code was set on the error response, treat it as a client error. + if statusCode == 0 { + statusCode = http.StatusBadRequest + } return statusCode, actual.Message, actual.Content default: - return statusCode, err.Error(), nil + // Any non-validation error is treated as an internal server error with a generic message. + // The full error (including DB/sqlx failures) is still available in logs via exec.Context.SetError(err). + return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil } } diff --git a/repository/resource/service.go b/repository/resource/service.go index d1104e891..19d098b54 100644 --- a/repository/resource/service.go +++ b/repository/resource/service.go @@ -3,6 +3,10 @@ package resource import ( "context" "fmt" + "strings" + "sync" + "time" + "github.com/viant/afs" "github.com/viant/afs/file" "github.com/viant/afs/storage" @@ -10,9 +14,6 @@ import ( "github.com/viant/cloudless/resource" "github.com/viant/datly/repository/version" "github.com/viant/datly/view" - "strings" - "sync" - "time" ) type ( From 7739b70e7767b94b4b721eb4a920d6da84de20c6 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 16 Dec 2025 07:16:32 -0800 Subject: [PATCH 104/117] error reclassification --- go.mod | 104 ++++++++++++++++++++++++++++----------------------------- go.sum | 52 +++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 52 deletions(-) diff --git a/go.mod b/go.mod index 00d915490..86c7d5b3a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/viant/datly -go 1.23.8 +go 1.25.0 require ( github.com/aerospike/aerospike-client-go v4.5.2+incompatible @@ -14,9 +14,9 @@ require ( github.com/lib/pq v1.10.6 github.com/mattn/go-sqlite3 v1.14.16 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.10.0 + github.com/stretchr/testify v1.11.1 github.com/viant/afs v1.26.2 - github.com/viant/afsc v1.9.1 + github.com/viant/afsc v1.16.0 github.com/viant/assertly v0.9.1-0.20220620174148-bab013f93a60 github.com/viant/bigquery v0.4.1 github.com/viant/cloudless v1.12.0 @@ -34,9 +34,9 @@ require ( github.com/viant/velty v0.2.1-0.20230927172116-ba56497b5c85 github.com/viant/xreflect v0.7.3 github.com/viant/xunsafe v0.10.3 - golang.org/x/mod v0.25.0 - golang.org/x/oauth2 v0.30.0 - google.golang.org/api v0.174.0 + golang.org/x/mod v0.28.0 + golang.org/x/oauth2 v0.32.0 + google.golang.org/api v0.201.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -60,58 +60,58 @@ require ( github.com/viant/xdatly/types/custom v0.0.0-20240801144911-4c2bfca4c23a github.com/viant/xlsy v0.3.1 github.com/viant/xmlify v0.1.1 - golang.org/x/net v0.40.0 - golang.org/x/tools v0.33.0 + golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 + golang.org/x/tools v0.37.0 modernc.org/sqlite v1.18.1 ) require ( - cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/auth v0.2.0 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.0 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/firestore v1.15.0 // indirect - cloud.google.com/go/iam v1.1.7 // indirect - cloud.google.com/go/longrunning v0.5.5 // indirect - cloud.google.com/go/secretmanager v1.11.5 // indirect - cloud.google.com/go/storage v1.40.0 // indirect + cloud.google.com/go v0.116.0 // indirect + cloud.google.com/go/auth v0.9.8 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/firestore v1.17.0 // indirect + cloud.google.com/go/iam v1.2.1 // indirect + cloud.google.com/go/longrunning v0.6.1 // indirect + cloud.google.com/go/secretmanager v1.14.1 // indirect + cloud.google.com/go/storage v1.45.0 // indirect firebase.google.com/go v3.13.0+incompatible // indirect firebase.google.com/go/v4 v4.14.0 // indirect github.com/MicahParks/keyfunc v1.9.0 // indirect github.com/aerospike/aerospike-client-go/v6 v6.15.1 // indirect github.com/aws/aws-sdk-go v1.51.23 // indirect - github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/config v1.27.11 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.26 // indirect + github.com/aws/aws-sdk-go-v2 v1.32.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.28.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.41 // indirect github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect github.com/aws/aws-sdk-go-v2/service/sns v1.31.3 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.22.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect - github.com/aws/smithy-go v1.20.3 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect + github.com/aws/smithy-go v1.22.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-errors/errors v1.5.1 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/s2a-go v0.1.7 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/google/s2a-go v0.1.8 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect @@ -124,7 +124,7 @@ require ( github.com/mazznoer/csscolorparser v0.1.3 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/nxadm/tail v1.4.8 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect @@ -136,24 +136,24 @@ require ( github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect github.com/yuin/gopher-lua v1.1.1 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/sync v0.15.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect - golang.org/x/time v0.5.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/term v0.36.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/time v0.7.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine/v2 v2.0.2 // indirect - google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect + google.golang.org/grpc v1.77.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect modernc.org/cc/v3 v3.36.3 // indirect diff --git a/go.sum b/go.sum index 8ed5f2096..54847327f 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,7 @@ cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMz cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -104,8 +105,10 @@ cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= cloud.google.com/go/auth v0.2.0 h1:y6oTcpMSbOcXbwYgUUrvI+mrQ2xbrcdpPgtVbCGTLTk= cloud.google.com/go/auth v0.2.0/go.mod h1:+yb+oy3/P0geX6DLKlqiGHARGR6EX2GRtYCzWOCQSbU= +cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.0 h1:FR8zevgQwu+8CqiOT5r6xCmJa3pJC/wdXEEPF1OkNhA= cloud.google.com/go/auth/oauth2adapt v0.2.0/go.mod h1:AfqujpDAlTfLfeCIl/HJZZlIxD8+nJoZ5e0x1IxGq5k= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= @@ -188,6 +191,7 @@ cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxB cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -285,6 +289,7 @@ cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466d cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8= cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= +cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y= cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= @@ -325,6 +330,7 @@ cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= +cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= @@ -359,6 +365,7 @@ cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= @@ -492,6 +499,7 @@ cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8A cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY= cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= +cloud.google.com/go/secretmanager v1.14.1/go.mod h1:L+gO+u2JA9CCyXpSR8gDH0o8EV7i/f0jdBOrUXcIV0U= cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= @@ -549,6 +557,7 @@ cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5og cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= +cloud.google.com/go/storage v1.45.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -654,22 +663,29 @@ github.com/aws/aws-sdk-go v1.51.23/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3Tj github.com/aws/aws-sdk-go-v2 v1.17.2/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= +github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA= github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE= +github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= github.com/aws/aws-sdk-go-v2/credentials v1.17.26 h1:tsm8g/nJxi8+/7XyJJcP2dLrnK/5rkFp6+i2nhmz5fk= github.com/aws/aws-sdk-go-v2/credentials v1.17.26/go.mod h1:3vAM49zkIa3q8WT6o9Ve5Z0vdByDMwmdScO0zvThTgI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7 h1:CyuByiiCA4lPfU8RaHJh2wIYYn0hkFlOkMfWkVY67Mc= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7/go.mod h1:pAMtgCPVxcKohC/HNI6nLwLeW007eYl3T+pq7yTMV3o= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26/go.mod h1:2E0LdbJW6lbeU4uxjum99GZzI0ZjDpAb0CoSCM0oeEY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20/go.mod h1:/+6lSiby8TBFpTVXZgKiN/rCfkYXEGvhlM4zCgPpt7w= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8 h1:VgdGaSIoH4JhUZIspT8UgK0aBF85TiLve7VHEx3NfqE= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8/go.mod h1:jvXzk+hVrlkiQOvnq6jH+F6qBK0CEceXkEWugT+4Kdc= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27 h1:7MhqbR+k+b0gbOxp+W8yXgsl/Z5/dtMh85K0WI8X2EA= @@ -677,23 +693,29 @@ github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27/go.mod h1:wX9QEZJ8 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20 h1:kSZR22oLBDMtP8ZPGXhz649NU77xsJDG7g3xfT6nHVk= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20/go.mod h1:lxM5qubwGNX29Qy+xTFG8G0r2Mj/TmyC+h3hS/7E4V8= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= github.com/aws/aws-sdk-go-v2/service/sns v1.31.3 h1:eSTEdxkfle2G98FE+Xl3db/XAXXVTJPNQo9K/Ar8oAI= github.com/aws/aws-sdk-go-v2/service/sns v1.31.3/go.mod h1:1dn0delSO3J69THuty5iwP0US2Glt0mx2qBBlI13pvw= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 h1:Vjqy5BZCOIsn4Pj8xzyqgGmsSqzz7y/WXbN3RgOoVrc= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3/go.mod h1:L0enV3GCRd5iG9B64W35C4/hwsCB00Ib+DKVGTadKHI= github.com/aws/aws-sdk-go-v2/service/sso v1.22.3 h1:Fv1vD2L65Jnp5QRsdiM64JvUM4Xe+E0JyVsRQKv6IeA= github.com/aws/aws-sdk-go-v2/service/sso v1.22.3/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -727,6 +749,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= @@ -776,6 +799,7 @@ github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpx github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -890,6 +914,7 @@ github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkj github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -901,6 +926,7 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5 github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -919,6 +945,7 @@ github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2e github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -1021,6 +1048,7 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1089,6 +1117,7 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= @@ -1098,6 +1127,8 @@ github.com/viant/afs v1.26.2 h1:rOs/iFxFlEndhIRATJVXlNWhVU0cGdRQAGVTVJPdsc0= github.com/viant/afs v1.26.2/go.mod h1:rScbFd9LJPGTM8HOI8Kjwee0AZ+MZMupAvFpPg+Qdj4= github.com/viant/afsc v1.9.1 h1:BIus7fYyjM+MDgKuAzCBfoV4oVy2xTVhuFsQKUCPvkQ= github.com/viant/afsc v1.9.1/go.mod h1:FA/xVjaMM10qGByabP8anTVMH6N4eUsAeWm5xcEZJJA= +github.com/viant/afsc v1.16.0 h1:/kOH/flNwme6h3oFrU/KPnMHkhbCZxQncTf1GSQIlBQ= +github.com/viant/afsc v1.16.0/go.mod h1:Z6fP3VcmzS8Sg2lowctR6KkVEX7XxJ8aNaoHqhUiZkY= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/assertly v0.9.0/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/assertly v0.9.1-0.20220620174148-bab013f93a60 h1:VFJvCOHKXv4IqX8rJwn1otpHWQGgMDv2bXtAPgEzndM= @@ -1202,16 +1233,21 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -1239,6 +1275,7 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1303,6 +1340,7 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1374,6 +1412,7 @@ golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1409,6 +1448,7 @@ golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1430,6 +1470,7 @@ golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1523,6 +1564,7 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1540,6 +1582,7 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1561,6 +1604,7 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1570,6 +1614,7 @@ golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1636,6 +1681,7 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1720,6 +1766,7 @@ google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2 google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.174.0 h1:zB1BWl7ocxfTea2aQ9mgdzXjnfPySllpPOskdnO+q34= google.golang.org/api v0.174.0/go.mod h1:aC7tB6j0HR1Nl0ni5ghpx6iLasmAX78Zkh/wgxAAjLg= +google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1874,12 +1921,14 @@ google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc= google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= +google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= @@ -1887,6 +1936,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1933,6 +1983,7 @@ google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3 google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1954,6 +2005,7 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= From 4ba19cc59bedfe0bc8c2e769a4ed9f559854a5a0 Mon Sep 17 00:00:00 2001 From: Terry Zhao Date: Tue, 16 Dec 2025 08:32:42 -0800 Subject: [PATCH 105/117] init view schema if nil --- repository/components.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/repository/components.go b/repository/components.go index c803bcd3f..536ad3292 100644 --- a/repository/components.go +++ b/repository/components.go @@ -236,6 +236,9 @@ func (c *Components) updateIOTypeDependencies(ctx context.Context, ioType *state aView = baseView } } + if aView.Schema == nil { + aView.Schema = parameterViewSchema(parameter) + } aView.Schema.SetType(parameter.Schema.Type()) } } From 3a03b8e323cb8dee7a980e5a1e237808a7331b9e Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 16 Dec 2025 20:06:48 -0800 Subject: [PATCH 106/117] error reclassification --- go.mod | 23 ++++++++ go.sum | 93 ++++++++++++++++++++++++++++++ internal/inference/state.go | 7 +++ service/session/state.go | 111 ++++++++++++++++++++++-------------- 4 files changed, 191 insertions(+), 43 deletions(-) diff --git a/go.mod b/go.mod index 86c7d5b3a..5f5213887 100644 --- a/go.mod +++ b/go.mod @@ -66,6 +66,7 @@ require ( ) require ( + cel.dev/expr v0.24.0 // indirect cloud.google.com/go v0.116.0 // indirect cloud.google.com/go/auth v0.9.8 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect @@ -73,36 +74,53 @@ require ( cloud.google.com/go/firestore v1.17.0 // indirect cloud.google.com/go/iam v1.2.1 // indirect cloud.google.com/go/longrunning v0.6.1 // indirect + cloud.google.com/go/monitoring v1.21.1 // indirect cloud.google.com/go/secretmanager v1.14.1 // indirect cloud.google.com/go/storage v1.45.0 // indirect firebase.google.com/go v3.13.0+incompatible // indirect firebase.google.com/go/v4 v4.14.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect github.com/MicahParks/keyfunc v1.9.0 // indirect github.com/aerospike/aerospike-client-go/v6 v6.15.1 // indirect github.com/aws/aws-sdk-go v1.51.23 // indirect github.com/aws/aws-sdk-go-v2 v1.32.2 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect github.com/aws/aws-sdk-go-v2/config v1.28.0 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.41 // indirect github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8 // indirect github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 // indirect + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.2 // indirect github.com/aws/aws-sdk-go-v2/service/sns v1.31.3 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect github.com/aws/smithy-go v1.22.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-errors/errors v1.5.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -128,6 +146,7 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/viant/gosh v0.2.1 // indirect github.com/viant/igo v0.2.0 // indirect github.com/viant/x v0.3.0 // indirect @@ -136,10 +155,14 @@ require ( github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a // indirect github.com/yuin/gopher-lua v1.1.1 // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/sync v0.17.0 // indirect diff --git a/go.sum b/go.sum index 54847327f..b3ca5d156 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -41,6 +43,7 @@ cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMz cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= @@ -105,9 +108,11 @@ cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= cloud.google.com/go/auth v0.2.0 h1:y6oTcpMSbOcXbwYgUUrvI+mrQ2xbrcdpPgtVbCGTLTk= cloud.google.com/go/auth v0.2.0/go.mod h1:+yb+oy3/P0geX6DLKlqiGHARGR6EX2GRtYCzWOCQSbU= +cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8= cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.0 h1:FR8zevgQwu+8CqiOT5r6xCmJa3pJC/wdXEEPF1OkNhA= cloud.google.com/go/auth/oauth2adapt v0.2.0/go.mod h1:AfqujpDAlTfLfeCIl/HJZZlIxD8+nJoZ5e0x1IxGq5k= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= @@ -191,6 +196,7 @@ cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxB cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= @@ -289,6 +295,7 @@ cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466d cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8= cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= +cloud.google.com/go/firestore v1.17.0 h1:iEd1LBbkDZTFsLw3sTH50eyg4qe8eoG6CjocmEXO9aQ= cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y= cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= @@ -330,6 +337,7 @@ cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= +cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= @@ -365,6 +373,7 @@ cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= @@ -389,6 +398,8 @@ cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhI cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/monitoring v1.21.1 h1:zWtbIoBMnU5LP9A/fz8LmWMGHpk4skdfeiaa66QdFGc= +cloud.google.com/go/monitoring v1.21.1/go.mod h1:Rj++LKrlht9uBi8+Eb530dIrzG/cU/lB8mt+lbeFK1c= cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= @@ -499,6 +510,7 @@ cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8A cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY= cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= +cloud.google.com/go/secretmanager v1.14.1 h1:xlWSIg8rtBn5qCr2f3XtQP19+5COyf/ll49SEvi/0vM= cloud.google.com/go/secretmanager v1.14.1/go.mod h1:L+gO+u2JA9CCyXpSR8gDH0o8EV7i/f0jdBOrUXcIV0U= cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= @@ -557,6 +569,7 @@ cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5og cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= +cloud.google.com/go/storage v1.45.0 h1:5av0QcIVj77t+44mV4gffFC/LscFRUhto6UBMB5SimM= cloud.google.com/go/storage v1.45.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= @@ -637,6 +650,12 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 h1:8nn+rsCvTq9axyEh382S0PFLBeaFwNsT43IrPWzctRU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o= github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw= @@ -663,29 +682,42 @@ github.com/aws/aws-sdk-go v1.51.23/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3Tj github.com/aws/aws-sdk-go-v2 v1.17.2/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= +github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA= github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE= +github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ= github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= github.com/aws/aws-sdk-go-v2/credentials v1.17.26 h1:tsm8g/nJxi8+/7XyJJcP2dLrnK/5rkFp6+i2nhmz5fk= github.com/aws/aws-sdk-go-v2/credentials v1.17.26/go.mod h1:3vAM49zkIa3q8WT6o9Ve5Z0vdByDMwmdScO0zvThTgI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7 h1:CyuByiiCA4lPfU8RaHJh2wIYYn0hkFlOkMfWkVY67Mc= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7/go.mod h1:pAMtgCPVxcKohC/HNI6nLwLeW007eYl3T+pq7yTMV3o= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 h1:X+4YY5kZRI/cOoSMVMGTqFXHAMg1bvvay7IBcqHpybQ= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33/go.mod h1:DPynzu+cn92k5UQ6tZhX+wfTB4ah6QDU/NgdHqatmvk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26/go.mod h1:2E0LdbJW6lbeU4uxjum99GZzI0ZjDpAb0CoSCM0oeEY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20/go.mod h1:/+6lSiby8TBFpTVXZgKiN/rCfkYXEGvhlM4zCgPpt7w= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 h1:7edmS3VOBDhK00b/MwGtGglCm7hhwNYnjJs/PgFdMQE= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21/go.mod h1:Q9o5h4HoIWG8XfzxqiuK/CGUbepCJ8uTlaE3bAbxytQ= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8 h1:VgdGaSIoH4JhUZIspT8UgK0aBF85TiLve7VHEx3NfqE= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8/go.mod h1:jvXzk+hVrlkiQOvnq6jH+F6qBK0CEceXkEWugT+4Kdc= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27 h1:7MhqbR+k+b0gbOxp+W8yXgsl/Z5/dtMh85K0WI8X2EA= @@ -693,28 +725,44 @@ github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27/go.mod h1:wX9QEZJ8 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 h1:4FMHqLfk0efmTqhXVRL5xYRqlEBNBiRI7N6w4jsEdd4= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2/go.mod h1:LWoqeWlK9OZeJxsROW2RqrSPvQHKTpp69r/iDjwsSaw= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20 h1:kSZR22oLBDMtP8ZPGXhz649NU77xsJDG7g3xfT6nHVk= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20/go.mod h1:lxM5qubwGNX29Qy+xTFG8G0r2Mj/TmyC+h3hS/7E4V8= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt3E41huP+GvQZJD38WLsgVp4iOtAjg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2/go.mod h1:/niFCtmuQNxqx9v8WAPq5qh7EH25U4BF6tjoyq9bObM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 h1:xA6XhTF7PE89BCNHJbQi8VvPzcgMtmGC5dr8S8N7lHk= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.2 h1:Rrqru2wYkKQCS2IM5/JrgKUQIoNTqA6y/iuxkjzxC6M= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.2/go.mod h1:QuCURO98Sqee2AXmqDNxKXYFm2OEDAVAPApMqO0Vqnc= github.com/aws/aws-sdk-go-v2/service/sns v1.31.3 h1:eSTEdxkfle2G98FE+Xl3db/XAXXVTJPNQo9K/Ar8oAI= github.com/aws/aws-sdk-go-v2/service/sns v1.31.3/go.mod h1:1dn0delSO3J69THuty5iwP0US2Glt0mx2qBBlI13pvw= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 h1:Vjqy5BZCOIsn4Pj8xzyqgGmsSqzz7y/WXbN3RgOoVrc= github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3/go.mod h1:L0enV3GCRd5iG9B64W35C4/hwsCB00Ib+DKVGTadKHI= +github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2 h1:z6Pq4+jtKlhK4wWJGHRGwMLGjC1HZwAO3KJr/Na0tSU= +github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2/go.mod h1:DSmu/VZzpQlAubWBbAvNpt+S4k/XweglJi4XaDGyvQk= github.com/aws/aws-sdk-go-v2/service/sso v1.22.3 h1:Fv1vD2L65Jnp5QRsdiM64JvUM4Xe+E0JyVsRQKv6IeA= github.com/aws/aws-sdk-go-v2/service/sso v1.22.3/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo= github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -724,9 +772,12 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -744,6 +795,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -767,10 +820,15 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= +github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= +github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -794,11 +852,14 @@ github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmn github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= @@ -914,6 +975,7 @@ github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkj github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -926,6 +988,7 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5 github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= @@ -945,6 +1008,7 @@ github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2e github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -1101,6 +1165,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -1231,22 +1297,35 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -1275,6 +1354,7 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1340,6 +1420,7 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1412,6 +1493,7 @@ golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1448,6 +1530,7 @@ golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1470,6 +1553,7 @@ golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1564,6 +1648,7 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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= @@ -1604,6 +1689,7 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1614,6 +1700,7 @@ golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1766,6 +1853,7 @@ google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2 google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.174.0 h1:zB1BWl7ocxfTea2aQ9mgdzXjnfPySllpPOskdnO+q34= google.golang.org/api v0.174.0/go.mod h1:aC7tB6j0HR1Nl0ni5ghpx6iLasmAX78Zkh/wgxAAjLg= +google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0= google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1921,6 +2009,7 @@ google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -1928,6 +2017,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go. google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc= google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= +google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= @@ -1936,6 +2026,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= @@ -1983,6 +2074,7 @@ google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3 google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -2005,6 +2097,7 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/inference/state.go b/internal/inference/state.go index 2783c2767..e309bc01f 100644 --- a/internal/inference/state.go +++ b/internal/inference/state.go @@ -785,6 +785,13 @@ func discoverStateType(baseDir string, types *xreflect.Types, dataType string, p return nil, err } var rType = xunsafe.LookupType(dirTypes.ModulePath + "/" + dataType) + + if rType == nil && types != nil && strings.Count(pkg, "/") > 1 { //the last resort fallback collission protection + pkg = strings.Replace(pkg, "pkg/", "", 1) + rType, _ = types.Lookup(dataType, xreflect.WithPackage(pkg)) + + } + if rType == nil && len(stateTypeFields) > 0 { rType = reflect.StructOf(stateTypeFields) } diff --git a/service/session/state.go b/service/session/state.go index 2808c04e1..60f614d42 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -317,9 +317,12 @@ func (s *Session) populateParameter(ctx context.Context, parameter *state.Parame //ensure last written can be shared if err == nil { + switch parameterSelector.Type().Kind() { case reflect.Ptr: - s.cache.put(parameter, parameterSelector.Value(aState.Pointer())) + if parameter.Schema.Type() == parameterSelector.Type() { + s.cache.put(parameter, parameterSelector.Value(aState.Pointer())) + } } } return err @@ -402,9 +405,8 @@ func (s *Session) ensureValidValue(value interface{}, parameter *state.Parameter } } case reflect.Slice: - ptr := xunsafe.AsPointer(value) - slice := parameter.Schema.Slice() - sliceLen := slice.Len(ptr) + rSlice := reflect.ValueOf(value) + sliceLen := rSlice.Len() if errorMessage := validateSliceParameter(parameter, sliceLen); errorMessage != "" { return nil, errors.New(errorMessage) } @@ -415,11 +417,32 @@ func (s *Session) ensureValidValue(value interface{}, parameter *state.Parameter default: switch sliceLen { case 0: - value = reflect.New(parameter.OutputType().Elem()).Elem().Interface() + switch outputType.Kind() { + case reflect.Ptr: + value = reflect.New(outputType.Elem()).Elem().Interface() + case reflect.Struct: + value = reflect.New(outputType).Elem().Interface() + default: + value = reflect.New(outputType).Elem().Interface() + } valueType = reflect.TypeOf(value) case 1: - value = slice.ValuePointerAt(ptr, 0) - valueType = reflect.TypeOf(value) + elem := rSlice.Index(0) + if elem.Kind() == reflect.Interface && !elem.IsNil() { + elem = elem.Elem() + } + if elem.Kind() == reflect.Ptr { + value = elem.Interface() + valueType = elem.Type() + break + } + if elem.CanAddr() { + value = elem.Addr().Interface() + valueType = elem.Addr().Type() + break + } + value = elem.Interface() + valueType = elem.Type() default: return nil, fmt.Errorf("parameter %v return more than one value, len: %v rows ", parameter.Name, sliceLen) } @@ -437,53 +460,55 @@ func (s *Session) ensureValidValue(value interface{}, parameter *state.Parameter } if parameter.Schema.IsStruct() && !(valueType == selector.Type() || valueType.ConvertibleTo(selector.Type()) || valueType.AssignableTo(selector.Type())) { - - rawSelectorType := selector.Type() - isSelectorPtr := false - if rawSelectorType.Kind() == reflect.Ptr { - rawSelectorType = rawSelectorType.Elem() - isSelectorPtr = true + destType := selector.Type() + rawDestType := destType + destIsPtr := false + if rawDestType.Kind() == reflect.Ptr { + rawDestType = rawDestType.Elem() + destIsPtr = true } - isValuePtr := false - rawValueType := valueType - if rawValueType.Kind() == reflect.Ptr { - rawValueType = valueType.Elem() - isValuePtr = true + + rawSrcType := valueType + srcIsPtr := false + if rawSrcType.Kind() == reflect.Ptr { + rawSrcType = rawSrcType.Elem() + srcIsPtr = true } - if rawSelectorType.Kind() == reflect.Struct && isSelectorPtr { - if rawValueType.ConvertibleTo(rawSelectorType) { - ptrValue := reflect.ValueOf(value) - if isValuePtr && ptrValue.IsNil() { + if rawDestType.Kind() == reflect.Struct && rawSrcType.Kind() == reflect.Struct && rawSrcType.ConvertibleTo(rawDestType) { + srcValue := reflect.ValueOf(value) + if srcIsPtr { + if srcValue.IsNil() { return nil, nil } - var destValue reflect.Value - if isValuePtr { - destValue = ptrValue.Elem().Convert(rawSelectorType) - } else { - destValue = ptrValue.Convert(rawSelectorType) - } - if isSelectorPtr { - destPtrType := reflect.New(valueType) - destPtrType.Elem().Set(destValue) - return destPtrType.Interface(), nil - } else { - return destValue.Interface(), nil - } + srcValue = srcValue.Elem() } + converted := srcValue.Convert(rawDestType) + if destIsPtr { + out := reflect.New(rawDestType) + out.Elem().Set(converted) + return out.Interface(), nil + } + return converted.Interface(), nil } if options.shallReportNotAssignable() { - //if !ensureAssignable(parameter.Name, selector.Type(), valueType) { - fmt.Printf("parameter %v is not directly assignable from %s:(%s)\nsrc:%s \ndst:%s\n", parameter.Name, parameter.In.Kind, parameter.In.Name, valueType.String(), selector.Type().String()) - //} + fmt.Printf("parameter %v is not directly assignable from %s:(%s)\nsrc:%s \ndst:%s\n", parameter.Name, parameter.In.Kind, parameter.In.Name, valueType.String(), destType.String()) } - reflectValue := reflect.New(valueType) //TODO replace with fast xreflect copy - valuePtr := reflectValue.Interface() + var target reflect.Value + if destIsPtr { + target = reflect.New(rawDestType) // *T where destType is *T + } else { + target = reflect.New(destType) // *T where destType is T + } if data, err := json.Marshal(value); err == nil { - if err = json.Unmarshal(data, valuePtr); err == nil { - value = reflectValue.Elem().Interface() + if err = json.Unmarshal(data, target.Interface()); err == nil { + if destIsPtr { + value = target.Interface() + } else { + value = target.Elem().Interface() + } } } } @@ -841,7 +866,7 @@ func (s *Session) LoadState(parameters state.Parameters, aState interface{}, opt func (s *Session) handleParameterError(parameter *state.Parameter, err error, errors *response.Errors) { if parameter.ErrorMessage != "" && err != nil { msg := strings.ReplaceAll(parameter.ErrorMessage, "${error}", err.Error()) - err = fmt.Errorf(msg) + err = fmt.Errorf("%s", msg) } if pErr, ok := err.(*response.Error); ok { pErr.Code = parameter.ErrorStatusCode From 5bd0dee576c25bfc2657da019edad895cbf80b4d Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 16 Dec 2025 20:40:33 -0800 Subject: [PATCH 107/117] error reclassification --- service/session/state_test.go | 291 ++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 service/session/state_test.go diff --git a/service/session/state_test.go b/service/session/state_test.go new file mode 100644 index 000000000..497d6aca6 --- /dev/null +++ b/service/session/state_test.go @@ -0,0 +1,291 @@ +package session + +import ( + "reflect" + "testing" + + "github.com/viant/datly/view/state" + "github.com/viant/structology" +) + +func TestSessionEnsureValidValue_Transitions(t *testing.T) { + type T struct { + A *int + B *int + } + + inlineStructSwapped := reflect.StructOf([]reflect.StructField{ + // Deliberately swap field order vs T to ensure the types are not convertible. + {Name: "B", Type: reflect.TypeOf((*int)(nil))}, + {Name: "A", Type: reflect.TypeOf((*int)(nil))}, + }) + inlinePtrType := reflect.PtrTo(inlineStructSwapped) + + newSelector := func(t *testing.T, paramType reflect.Type) *structology.Selector { + t.Helper() + stateStruct := reflect.StructOf([]reflect.StructField{ + {Name: "Param", Type: paramType}, + }) + stateType := structology.NewStateType(stateStruct) + selector := stateType.Lookup("Param") + if selector == nil { + t.Fatalf("failed to lookup selector Param") + } + return selector + } + + intPtrType := reflect.TypeOf((*int)(nil)) + + ttPtrType := reflect.TypeOf((*T)(nil)) + sliceOfTTPtrType := reflect.SliceOf(ttPtrType) + ptrToSliceOfTTPtrType := reflect.PtrTo(sliceOfTTPtrType) + intType := reflect.TypeOf(int(0)) + sliceOfIntType := reflect.SliceOf(intType) + ttType := reflect.TypeOf(T{}) + + boolPtr := func(v bool) *bool { return &v } + + cases := []struct { + name string + schemaType reflect.Type + selectorType reflect.Type + required *bool + value interface{} + wantType reflect.Type + wantErr bool + check func(t *testing.T, got interface{}) + }{ + { + name: "nil-value_ptr-schema_returns-typed-nil", + schemaType: intPtrType, + selectorType: intPtrType, + value: nil, + wantType: intPtrType, + check: func(t *testing.T, got interface{}) { + t.Helper() + if !reflect.ValueOf(got).IsNil() { + t.Fatalf("expected nil pointer, got %v", got) + } + }, + }, + { + name: "nil-value_slice-schema_returns-nil-slice", + schemaType: sliceOfIntType, + selectorType: sliceOfIntType, + value: nil, + wantType: sliceOfIntType, + check: func(t *testing.T, got interface{}) { + t.Helper() + if !reflect.ValueOf(got).IsNil() { + t.Fatalf("expected nil slice, got %v", got) + } + }, + }, + { + name: "ptr-struct_to_ptr-to-slice-wraps-single", + schemaType: sliceOfTTPtrType, + selectorType: ptrToSliceOfTTPtrType, + value: func() interface{} { + a := 10 + b := 20 + return &T{A: &a, B: &b} + }(), + wantType: ptrToSliceOfTTPtrType, + check: func(t *testing.T, got interface{}) { + t.Helper() + gotSlicePtr := reflect.ValueOf(got) + if gotSlicePtr.IsNil() { + t.Fatalf("expected non-nil pointer to slice") + } + gotSlice := gotSlicePtr.Elem() + if gotSlice.Len() != 1 { + t.Fatalf("expected len=1, got %d", gotSlice.Len()) + } + if gotSlice.Index(0).IsNil() { + t.Fatalf("expected element 0 to be non-nil") + } + }, + }, + { + name: "ptr-struct-nil_to_ptr-to-slice-wraps-empty", + schemaType: sliceOfTTPtrType, + selectorType: ptrToSliceOfTTPtrType, + value: (*T)(nil), + wantType: ptrToSliceOfTTPtrType, + check: func(t *testing.T, got interface{}) { + t.Helper() + gotSlicePtr := reflect.ValueOf(got) + if gotSlicePtr.IsNil() { + t.Fatalf("expected non-nil pointer to slice") + } + gotSlice := gotSlicePtr.Elem() + if gotSlice.Len() != 0 { + t.Fatalf("expected len=0, got %d", gotSlice.Len()) + } + }, + }, + { + name: "slice-to-scalar_len0_required_errors", + schemaType: ttPtrType, + selectorType: ttPtrType, + required: boolPtr(true), + value: []*T{}, + wantErr: true, + }, + { + name: "slice-to-scalar_len0_not-required_returns-zero", + schemaType: ttPtrType, + selectorType: ttPtrType, + value: []*T{}, + wantType: ttPtrType, + check: func(t *testing.T, got interface{}) { + t.Helper() + if reflect.ValueOf(got).IsNil() { + t.Fatalf("expected non-nil *T") + } + }, + }, + { + name: "slice-of-int_len1_to-int", + schemaType: intType, + selectorType: intType, + value: []int{7}, + wantType: intType, + check: func(t *testing.T, got interface{}) { + t.Helper() + if got.(int) != 7 { + t.Fatalf("expected 7, got %v", got) + } + }, + }, + { + name: "slice-of-int_len2_to-int_errors", + schemaType: intType, + selectorType: intType, + value: []int{1, 2}, + wantErr: true, + }, + { + name: "ptr-required_nil_errors", + schemaType: ttPtrType, + selectorType: ttPtrType, + required: boolPtr(true), + value: (*T)(nil), + wantErr: true, + }, + { + name: "ptr-value_to-struct-selector_derefs", + schemaType: ttType, + selectorType: ttType, + value: func() interface{} { + a := 3 + b := 4 + return &T{A: &a, B: &b} + }(), + wantType: ttType, + check: func(t *testing.T, got interface{}) { + t.Helper() + gotT := got.(T) + if gotT.A == nil || gotT.B == nil { + t.Fatalf("expected non-nil fields") + } + if *gotT.A != 3 || *gotT.B != 4 { + t.Fatalf("unexpected values: %+v", gotT) + } + }, + }, + { + name: "struct-value_to-ptr-selector_allocates", + schemaType: ttPtrType, + selectorType: ttPtrType, + value: func() interface{} { + a := 5 + b := 6 + return T{A: &a, B: &b} + }(), + wantType: ttPtrType, + check: func(t *testing.T, got interface{}) { + t.Helper() + gotPtr := got.(*T) + if gotPtr == nil || gotPtr.A == nil || gotPtr.B == nil { + t.Fatalf("expected non-nil *T with non-nil fields") + } + if *gotPtr.A != 5 || *gotPtr.B != 6 { + t.Fatalf("unexpected values: %+v", *gotPtr) + } + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + parameter := &state.Parameter{ + Name: "Param", + In: state.NewState("Param"), + Schema: state.NewSchema(tc.schemaType), + Required: tc.required, + } + + selector := newSelector(t, tc.selectorType) + sess := &Session{} + opts := NewOptions(WithReportNotAssignable(false)) + + got, err := sess.ensureValidValue(tc.value, parameter, selector, opts) + if (err != nil) != tc.wantErr { + t.Fatalf("error=%v, wantErr=%v", err, tc.wantErr) + } + if tc.wantErr { + return + } + if tc.wantType != nil && reflect.TypeOf(got) != tc.wantType { + t.Fatalf("expected %v, got %T", tc.wantType, got) + } + if tc.check != nil { + tc.check(t, got) + } + }) + } + + t.Run("slice-of-named-ptr_to-inline-ptr_allocates-and-copies_details", func(t *testing.T) { + a := 1 + b := 2 + original := &T{A: &a, B: &b} + input := []*T{original} + + parameter := &state.Parameter{ + Name: "Param", + In: state.NewState("Param"), + Schema: state.NewSchema(inlinePtrType), + } + selector := newSelector(t, inlinePtrType) + sess := &Session{} + opts := NewOptions(WithReportNotAssignable(false)) + + got, err := sess.ensureValidValue(input, parameter, selector, opts) + if err != nil { + t.Fatalf("ensureValidValue error: %v", err) + } + if reflect.TypeOf(got) != inlinePtrType { + t.Fatalf("expected %v, got %T", inlinePtrType, got) + } + + gotPtr := reflect.ValueOf(got).Pointer() + origPtr := reflect.ValueOf(original).Pointer() + if gotPtr == origPtr { + t.Fatalf("expected ensureValidValue to allocate/copy into %v; got aliases original *T pointer %x", inlinePtrType, gotPtr) + } + + gotValue := reflect.ValueOf(got).Elem() + gotA := gotValue.FieldByName("A") + gotB := gotValue.FieldByName("B") + if gotA.IsNil() || gotB.IsNil() { + t.Fatalf("expected A and B to be non-nil") + } + if gotA.Elem().Int() != int64(*original.A) { + t.Fatalf("expected A=%d, got %d", *original.A, gotA.Elem().Int()) + } + if gotB.Elem().Int() != int64(*original.B) { + t.Fatalf("expected B=%d, got %d", *original.B, gotB.Elem().Int()) + } + }) +} From 3ff3ba125d73070f3147faef0945afedc70fb8cf Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 16 Dec 2025 22:38:50 -0800 Subject: [PATCH 108/117] patched marshaller --- gateway/router/marshal/json/cache.go | 3 +++ gateway/router/marshal/json/marshaller_interface.go | 8 ++++++++ gateway/router/marshal/json/marshaller_slice.go | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/gateway/router/marshal/json/cache.go b/gateway/router/marshal/json/cache.go index d08a4704f..15c46e4b9 100644 --- a/gateway/router/marshal/json/cache.go +++ b/gateway/router/marshal/json/cache.go @@ -120,6 +120,9 @@ func (c *pathCache) loadOrGetMarshaller(rType reflect.Type, cfg *config.IOConfig } func (c *pathCache) getMarshaller(rType reflect.Type, config *config.IOConfig, path string, outputPath string, tag *format.Tag, options ...interface{}) (marshaler, error) { + if rType == nil { + return nil, fmt.Errorf("nil reflect.Type for path %q", path) + } if tag == nil { tag = &format.Tag{} } diff --git a/gateway/router/marshal/json/marshaller_interface.go b/gateway/router/marshal/json/marshaller_interface.go index c7da33fe9..4256327c2 100644 --- a/gateway/router/marshal/json/marshaller_interface.go +++ b/gateway/router/marshal/json/marshaller_interface.go @@ -47,7 +47,15 @@ func asInterface(xType *xunsafe.Type, pointer unsafe.Pointer) interface{} { func (i *interfaceMarshaller) MarshallObject(ptr unsafe.Pointer, sb *MarshallSession) error { value := i.AsInterface(ptr) + if value == nil { + sb.Write(nullBytes) + return nil + } rType := reflect.TypeOf(value) + if rType == nil { + sb.Write(nullBytes) + return nil + } marshaller, err := i.cache.loadMarshaller(rType, i.config, i.path, i.outputPath, i.tag) if err != nil { diff --git a/gateway/router/marshal/json/marshaller_slice.go b/gateway/router/marshal/json/marshaller_slice.go index 1ad341cef..51d90d3f4 100644 --- a/gateway/router/marshal/json/marshaller_slice.go +++ b/gateway/router/marshal/json/marshaller_slice.go @@ -151,7 +151,15 @@ func (s *sliceInterfaceMarshaller) MarshallObject(ptr unsafe.Pointer, sb *Marsha sb.WriteByte(',') } + if iface == nil { + sb.Write(nullBytes) + continue + } ifaceType := reflect.TypeOf(iface) + if ifaceType == nil { + sb.Write(nullBytes) + continue + } marshaller, err := s.cache.loadMarshaller(ifaceType, s.config, s.path, s.outputPath, s.tag) if err != nil { From 8f56405d07653eb5fe1846c37701875fcf0fe72b Mon Sep 17 00:00:00 2001 From: adranwit Date: Wed, 17 Dec 2025 13:36:16 -0800 Subject: [PATCH 109/117] patched marshaller --- gateway/router/status/error.go | 88 ++++++++++++++++++++++++++++------ service/session/state.go | 12 +++++ 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/gateway/router/status/error.go b/gateway/router/status/error.go index 876dde080..2318d100d 100644 --- a/gateway/router/status/error.go +++ b/gateway/router/status/error.go @@ -2,10 +2,10 @@ package status import ( "net/http" + "strings" "github.com/viant/datly/service/executor/expand" "github.com/viant/datly/utils/httputils" - "github.com/viant/datly/utils/types" "github.com/viant/govalidator" svalidator "github.com/viant/sqlx/io/validator" "github.com/viant/xdatly/handler/response" @@ -17,9 +17,12 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { case *response.Error: code := actual.StatusCode() if code == 0 { - code = http.StatusInternalServerError + code = statusCode } - // For explicit 4xx we trust the message, for 5xx we keep it generic. + if code == 0 { + code = http.StatusBadRequest + } + // For explicit 5xx we keep response generic, for 4xx we trust the configured message. if code >= http.StatusInternalServerError { return code, http.StatusText(http.StatusInternalServerError), nil } @@ -31,19 +34,44 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { ret := violations.MergeGoViolation(actual.Violations) return http.StatusBadRequest, actual.Error(), ret case *response.Errors: - // Treat aggregated errors as validation-like by default. - actual.SetStatusCode(http.StatusBadRequest) - for _, anError := range actual.Errors { - isObj := types.IsObject(anError.Err) - if isObj { - statusCode, anError.Message, anError.Object = NormalizeErr(anError.Err, http.StatusBadRequest) + // Respect existing status/message set on aggregated errors (often parameter-driven). + if actual.StatusCode() == 0 { + if statusCode == 0 { + actual.SetStatusCode(http.StatusBadRequest) } else { - statusCode, anError.Message, anError.Object = NormalizeErr(anError.Err, http.StatusBadRequest) - } - if statusCode > actual.StatusCode() { actual.SetStatusCode(statusCode) } } + if actual.Message == "" && len(actual.Errors) > 0 { + actual.Message = actual.Errors[0].Message + } + + for _, anError := range actual.Errors { + code := anError.StatusCode() + + switch { + case code >= http.StatusInternalServerError: + // Explicitly marked as server error at parameter level: generic message. + anError.Message = http.StatusText(http.StatusInternalServerError) + case code == 0: + // No explicit status on this parameter error; classify underlying cause. + innerStatus, innerMsg, innerObj := NormalizeErr(anError.Err, actual.StatusCode()) + anError.Code = innerStatus + if innerMsg != "" { + anError.Message = innerMsg + } + if innerObj != nil { + anError.Object = innerObj + } + code = innerStatus + default: + // 4xx with configured status/message – leave as defined on the parameter. + } + + if code > actual.StatusCode() { + actual.SetStatusCode(code) + } + } return actual.StatusCode(), actual.Message, actual.Errors case *expand.ErrorResponse: if actual.StatusCode != 0 { @@ -55,8 +83,38 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { } return statusCode, actual.Message, actual.Content default: - // Any non-validation error is treated as an internal server error with a generic message. - // The full error (including DB/sqlx failures) is still available in logs via exec.Context.SetError(err). - return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil + // Only DB-caused errors are mapped to 500 with a generic message. + if isDatabaseError(err) { + return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil + } + if statusCode == 0 { + statusCode = http.StatusBadRequest + } + return statusCode, err.Error(), nil + } +} + +// isDatabaseError detects errors that originate from DB/sqlx execution. +// These are the only errors that should be remapped to 500 with a generic message. +func isDatabaseError(err error) bool { + if err == nil { + return false } + msg := err.Error() + if msg == "" { + return false + } + + // Known DB-related error patterns from reader/executor paths. + if strings.Contains(msg, "database error occured while fetching Data") { + return true + } + if strings.Contains(msg, "error occured while connecting to database") { + return true + } + if strings.Contains(msg, "failed to get db:") { + return true + } + + return false } diff --git a/service/session/state.go b/service/session/state.go index 60f614d42..8c9bad387 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -428,6 +428,18 @@ func (s *Session) ensureValidValue(value interface{}, parameter *state.Parameter valueType = reflect.TypeOf(value) case 1: elem := rSlice.Index(0) + rawType := elem.Type() + if rawType.Kind() == reflect.Ptr { + rawType = rawType.Elem() + } + if rawType.Kind() == reflect.Interface { + rawType = rawType.Elem() + } + + if rawType.Kind() != reflect.Struct { + break + } + if elem.Kind() == reflect.Interface && !elem.IsNil() { elem = elem.Elem() } From 926929f67544909a318f0aac818d9bfdf299b4f4 Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 18 Dec 2025 08:21:56 -0800 Subject: [PATCH 110/117] patched marshaller --- gateway/router/status/error.go | 76 ++++++++++--------------- go.mod | 1 + go.sum | 3 + service/executor/extension/validator.go | 11 ++++ utils/errors/db.go | 50 ++++++++++++++++ 5 files changed, 96 insertions(+), 45 deletions(-) create mode 100644 utils/errors/db.go diff --git a/gateway/router/status/error.go b/gateway/router/status/error.go index 2318d100d..bc9c2a83f 100644 --- a/gateway/router/status/error.go +++ b/gateway/router/status/error.go @@ -2,9 +2,9 @@ package status import ( "net/http" - "strings" "github.com/viant/datly/service/executor/expand" + derrors "github.com/viant/datly/utils/errors" "github.com/viant/datly/utils/httputils" "github.com/viant/govalidator" svalidator "github.com/viant/sqlx/io/validator" @@ -34,28 +34,24 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { ret := violations.MergeGoViolation(actual.Violations) return http.StatusBadRequest, actual.Error(), ret case *response.Errors: - // Respect existing status/message set on aggregated errors (often parameter-driven). - if actual.StatusCode() == 0 { - if statusCode == 0 { - actual.SetStatusCode(http.StatusBadRequest) - } else { - actual.SetStatusCode(statusCode) - } + maxStatus := actual.StatusCode() + if maxStatus == 0 { + maxStatus = statusCode } - if actual.Message == "" && len(actual.Errors) > 0 { - actual.Message = actual.Errors[0].Message + if maxStatus == 0 { + maxStatus = http.StatusBadRequest } + hasServerError := maxStatus >= http.StatusInternalServerError for _, anError := range actual.Errors { code := anError.StatusCode() - switch { case code >= http.StatusInternalServerError: - // Explicitly marked as server error at parameter level: generic message. anError.Message = http.StatusText(http.StatusInternalServerError) + hasServerError = true case code == 0: - // No explicit status on this parameter error; classify underlying cause. - innerStatus, innerMsg, innerObj := NormalizeErr(anError.Err, actual.StatusCode()) + innerStatus, innerMsg, innerObj := NormalizeErr(anError.Err, maxStatus) + code = innerStatus anError.Code = innerStatus if innerMsg != "" { anError.Message = innerMsg @@ -63,16 +59,31 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { if innerObj != nil { anError.Object = innerObj } - code = innerStatus + if code >= http.StatusInternalServerError { + hasServerError = true + } default: - // 4xx with configured status/message – leave as defined on the parameter. + if code >= http.StatusInternalServerError { + hasServerError = true + } } - if code > actual.StatusCode() { - actual.SetStatusCode(code) + if code > maxStatus { + maxStatus = code } } - return actual.StatusCode(), actual.Message, actual.Errors + + if hasServerError { + actual.Message = http.StatusText(http.StatusInternalServerError) + } else if actual.Message == "" && len(actual.Errors) > 0 { + actual.Message = actual.Errors[0].Message + } + + if maxStatus == 0 { + maxStatus = http.StatusBadRequest + } + + return maxStatus, actual.Message, actual.Errors case *expand.ErrorResponse: if actual.StatusCode != 0 { statusCode = actual.StatusCode @@ -84,7 +95,7 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { return statusCode, actual.Message, actual.Content default: // Only DB-caused errors are mapped to 500 with a generic message. - if isDatabaseError(err) { + if derrors.IsDatabaseError(err) { return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil } if statusCode == 0 { @@ -93,28 +104,3 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { return statusCode, err.Error(), nil } } - -// isDatabaseError detects errors that originate from DB/sqlx execution. -// These are the only errors that should be remapped to 500 with a generic message. -func isDatabaseError(err error) bool { - if err == nil { - return false - } - msg := err.Error() - if msg == "" { - return false - } - - // Known DB-related error patterns from reader/executor paths. - if strings.Contains(msg, "database error occured while fetching Data") { - return true - } - if strings.Contains(msg, "error occured while connecting to database") { - return true - } - if strings.Contains(msg, "failed to get db:") { - return true - } - - return false -} diff --git a/go.mod b/go.mod index 5f5213887..a5a9eab23 100644 --- a/go.mod +++ b/go.mod @@ -142,6 +142,7 @@ require ( github.com/mazznoer/csscolorparser v0.1.3 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/nxadm/tail v1.4.8 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect diff --git a/go.sum b/go.sum index b3ca5d156..38ca1e6c4 100644 --- a/go.sum +++ b/go.sum @@ -1110,6 +1110,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -1768,6 +1770,7 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/service/executor/extension/validator.go b/service/executor/extension/validator.go index 8c23f0df4..740b16f37 100644 --- a/service/executor/extension/validator.go +++ b/service/executor/extension/validator.go @@ -4,6 +4,8 @@ import ( "context" "database/sql" "fmt" + + derrors "github.com/viant/datly/utils/errors" "github.com/viant/datly/utils/httputils" "github.com/viant/govalidator" sqlxvalidator "github.com/viant/sqlx/io/validator" @@ -33,6 +35,9 @@ func (v *SqlxValidator) Validate(ctx context.Context, any interface{}, opts ...v err = v.validator.validateWithSqlx(ctx, any, validation, options) } if err != nil { + if derrors.IsDatabaseError(err) { + return validation, err + } validation.Append("/", "", "", "error", err.Error()) } return validation, nil @@ -46,9 +51,15 @@ func (v *Validator) Validate(ctx context.Context, any interface{}, opts ...valid validation := getOrCreateValidation(options) err := v.validateWithGoValidator(ctx, any, validation, options) if err != nil { + if derrors.IsDatabaseError(err) { + return validation, err + } validation.Append("/", "", "", "error", err.Error()) } if err = v.validateWithSqlx(ctx, any, validation, options); err != nil { + if derrors.IsDatabaseError(err) { + return validation, err + } validation.Append("/", "", "", "error", err.Error()) } return validation, nil diff --git a/utils/errors/db.go b/utils/errors/db.go new file mode 100644 index 000000000..19067f0ce --- /dev/null +++ b/utils/errors/db.go @@ -0,0 +1,50 @@ +package errors + +import ( + "errors" + "strings" +) + +// IsDatabaseError determines whether the supplied error was caused by the database or driver layer. +// We inspect the full error chain because many call-sites wrap driver errors with additional context. +func IsDatabaseError(err error) bool { + if err == nil { + return false + } + return hasDatabaseSignature(err) +} + +func hasDatabaseSignature(err error) bool { + for err != nil { + if matchesDatabasePattern(err.Error()) { + return true + } + err = errors.Unwrap(err) + } + return false +} + +func matchesDatabasePattern(message string) bool { + if message == "" { + return false + } + lower := strings.ToLower(message) + patterns := []string{ + "database error occured while fetching data", + "database error occurred while fetching data", + "error occured while connecting to database", + "error occurred while connecting to database", + "failed to get db", + "failed to create stmt source", + "too many connections", + "connection refused", + "driver: bad connection", + "sql: transaction has already been committed or rolled back", + } + for _, pattern := range patterns { + if strings.Contains(lower, pattern) { + return true + } + } + return false +} From af837488c6cf27f83b35f4f5fe700e4463343430 Mon Sep 17 00:00:00 2001 From: vc42 Date: Fri, 19 Dec 2025 13:54:24 -0500 Subject: [PATCH 111/117] use aState.Selector(parameter.Name) instead of parameter.Selector() to avoid SIGBUS --- service/session/state.go | 81 ++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/service/session/state.go b/service/session/state.go index 8c9bad387..7c2ff10df 100644 --- a/service/session/state.go +++ b/service/session/state.go @@ -285,6 +285,52 @@ func (s *Session) populateParameterInBackground(ctx context.Context, parameter * } } +// The function below causes SIGBUS when template parameters are rebound. +//E.g. a predicate builder velty expression is located in an embedded SQL, outside main DQL +//func (s *Session) populateParameter(ctx context.Context, parameter *state.Parameter, aState *structology.State, options *Options) error { +// value, has, err := s.LookupValue(ctx, parameter, options) +// if err != nil { +// return err +// } +// if !has { +// if parameter.IsRequired() { +// return fmt.Errorf("parameter %v is required", parameter.Name) +// } +// return nil +// } +// +// parameterSelector := parameter.Selector() +// if options.indirectState || parameterSelector == nil { //p +// parameterSelector, err = aState.Selector(parameter.Name) +// if parameterSelector == nil { +// switch parameter.In.Kind { +// case state.KindConst: +// return nil +// } +// } +// if err != nil { +// return err +// } +// } +// +// if value, err = s.ensureValidValue(value, parameter, parameterSelector, options); err != nil { +// return err +// } +// err = parameterSelector.SetValue(aState.Pointer(), value) +// +// //ensure last written can be shared +// if err == nil { +// +// switch parameterSelector.Type().Kind() { +// case reflect.Ptr: +// if parameter.Schema.Type() == parameterSelector.Type() { +// s.cache.put(parameter, parameterSelector.Value(aState.Pointer())) +// } +// } +// } +// return err +//} + func (s *Session) populateParameter(ctx context.Context, parameter *state.Parameter, aState *structology.State, options *Options) error { value, has, err := s.LookupValue(ctx, parameter, options) if err != nil { @@ -296,36 +342,25 @@ func (s *Session) populateParameter(ctx context.Context, parameter *state.Parame } return nil } - parameterSelector := parameter.Selector() - if options.indirectState || parameterSelector == nil { //p - parameterSelector, err = aState.Selector(parameter.Name) - if parameterSelector == nil { - switch parameter.In.Kind { - case state.KindConst: - return nil - } - } - if err != nil { - return err - } + + // Resolve selector strictly from the state's layout + // Treat "not found" as a no-op (skip), since this view doesn't declare that parameter. + parameterSelector, err := aState.Selector(parameter.Name) + if err != nil || parameterSelector == nil { + return nil } if value, err = s.ensureValidValue(value, parameter, parameterSelector, options); err != nil { return err } - err = parameterSelector.SetValue(aState.Pointer(), value) - - //ensure last written can be shared - if err == nil { + if err = parameterSelector.SetValue(aState.Pointer(), value); err != nil { + return err + } - switch parameterSelector.Type().Kind() { - case reflect.Ptr: - if parameter.Schema.Type() == parameterSelector.Type() { - s.cache.put(parameter, parameterSelector.Value(aState.Pointer())) - } - } + if parameterSelector.Type().Kind() == reflect.Ptr { + s.cache.put(parameter, parameterSelector.Value(aState.Pointer())) } - return err + return nil } func (s *Session) canRead(ctx context.Context, parameter *state.Parameter, opts *Options) (bool, error) { From cfe782336454bbe29058dc0a8d06fbd44ae658d9 Mon Sep 17 00:00:00 2001 From: adranwit Date: Mon, 22 Dec 2025 14:50:05 -0800 Subject: [PATCH 112/117] patched marshaller --- gateway/router/status/error.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gateway/router/status/error.go b/gateway/router/status/error.go index bc9c2a83f..41087fe5e 100644 --- a/gateway/router/status/error.go +++ b/gateway/router/status/error.go @@ -1,6 +1,7 @@ package status import ( + "errors" "net/http" "github.com/viant/datly/service/executor/expand" @@ -15,6 +16,11 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { violations := httputils.Violations{} switch actual := err.(type) { case *response.Error: + if derrors.IsDatabaseError(actual.Err) || derrors.IsDatabaseError(errors.New(actual.Message)) { + actual.Code = http.StatusInternalServerError + actual.Message = http.StatusText(http.StatusInternalServerError) + return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError), nil + } code := actual.StatusCode() if code == 0 { code = statusCode @@ -41,9 +47,15 @@ func NormalizeErr(err error, statusCode int) (int, string, interface{}) { if maxStatus == 0 { maxStatus = http.StatusBadRequest } - hasServerError := maxStatus >= http.StatusInternalServerError + hasServerError := maxStatus >= http.StatusInternalServerError || derrors.IsDatabaseError(errors.New(actual.Message)) for _, anError := range actual.Errors { + if derrors.IsDatabaseError(anError.Err) || derrors.IsDatabaseError(errors.New(anError.Message)) { + anError.Code = http.StatusInternalServerError + anError.Message = http.StatusText(http.StatusInternalServerError) + hasServerError = true + } + code := anError.StatusCode() switch { case code >= http.StatusInternalServerError: From 03ee2da17a88a34f18cdec47ec5a0bc5f80bb9b3 Mon Sep 17 00:00:00 2001 From: Himanshu Shishir Shah Date: Sun, 28 Dec 2025 20:52:47 -0800 Subject: [PATCH 113/117] ENG-52641: adding mutex to Options struct in locator --- view/state/kind/locator/options.go | 95 +++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/view/state/kind/locator/options.go b/view/state/kind/locator/options.go index 9cf99b2eb..18be24842 100644 --- a/view/state/kind/locator/options.go +++ b/view/state/kind/locator/options.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" "reflect" + "sync" "github.com/viant/datly/gateway/router/marshal/config" "github.com/viant/datly/gateway/router/marshal/json" @@ -21,6 +22,7 @@ import ( // Options represents locator options type ( Options struct { + mu sync.RWMutex request *http.Request Form *hstate.Form QuerySelectors hstate.QuerySelectors @@ -57,6 +59,9 @@ type ( ) func (o Options) LookupParameters(name string) *state.Parameter { + o.mu.RLock() + defer o.mu.RUnlock() + if len(o.InputParameters) > 0 { if ret, ok := o.InputParameters[name]; ok { return ret @@ -71,10 +76,17 @@ func (o Options) LookupParameters(name string) *state.Parameter { } func (o *Options) GetRequest() (*http.Request, error) { - return shared.CloneHTTPRequest(o.request) + o.mu.RLock() + req := o.request + o.mu.RUnlock() + + return shared.CloneHTTPRequest(req) } func (o *Options) UnmarshalFunc() Unmarshal { + o.mu.Lock() + defer o.mu.Unlock() + if o.Unmarshal != nil { return o.Unmarshal } @@ -101,6 +113,9 @@ var defaultURL, _ = url.Parse("http://localhost:8080/") // WithRequest create http requestState option func WithRequest(request *http.Request) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + ensureValueRequest(request) o.request = request } @@ -118,6 +133,9 @@ func ensureValueRequest(request *http.Request) { // WithCustom creates custom options func WithCustom(options ...interface{}) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Custom = options } } @@ -125,6 +143,9 @@ func WithCustom(options ...interface{}) Option { // WithURIPattern create Path pattern requestState func WithURIPattern(URI string) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.URIPattern = URI } } @@ -132,6 +153,9 @@ func WithURIPattern(URI string) Option { // WithBodyType create Body Type option func WithBodyType(rType reflect.Type) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.BodyType = rType } } @@ -139,6 +163,9 @@ func WithBodyType(rType reflect.Type) Option { // WithUnmarshal creates with unmarshal options func WithUnmarshal(fn func([]byte, interface{}) error) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Unmarshal = fn } } @@ -146,6 +173,9 @@ func WithUnmarshal(fn func([]byte, interface{}) error) Option { // WithParent creates with parent options func WithParent(locators *KindLocator) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Parent = locators } } @@ -153,12 +183,18 @@ func WithParent(locators *KindLocator) Option { // WithParameterLookup creates with parameter options func WithParameterLookup(lookupFn ParameterLookup) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.ParameterLookup = lookupFn } } func WithIOConfig(config *config.IOConfig) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.IOConfig = config } } @@ -166,6 +202,9 @@ func WithIOConfig(config *config.IOConfig) Option { // WithInputParameters creates with parameter options func WithInputParameters(parameters state.NamedParameters) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + if len(o.resourceConstants) == 0 { o.resourceConstants = make(map[string]interface{}) } @@ -184,6 +223,9 @@ func WithInputParameters(parameters state.NamedParameters) Option { func WithQuerySelectors(selectors hstate.QuerySelectors) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.QuerySelectors = selectors } } @@ -191,12 +233,18 @@ func WithQuerySelectors(selectors hstate.QuerySelectors) Option { // WithPathParameters create with path parameters options func WithPathParameters(parameters map[string]string) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Path = parameters } } func WithReadInto(fn ReadInto) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.ReadInto = fn } } @@ -204,6 +252,9 @@ func WithReadInto(fn ReadInto) Option { // WithViews returns with views options func WithViews(views view.NamedViews) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Views = views } } @@ -211,12 +262,18 @@ func WithViews(views view.NamedViews) Option { // WithState returns with satte options func WithState(state *structology.State) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.State = state } } func WithOutputParameters(parameters state.Parameters) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.OutputParameters = parameters.Index() } } @@ -224,6 +281,9 @@ func WithOutputParameters(parameters state.Parameters) Option { // WithDispatcher returns options to set dispatcher func WithDispatcher(dispatcher contract.Dispatcher) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Dispatcher = dispatcher } } @@ -231,6 +291,9 @@ func WithDispatcher(dispatcher contract.Dispatcher) Option { // WithView returns options to set view func WithView(aView *view.View) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.View = aView } } @@ -238,6 +301,9 @@ func WithView(aView *view.View) Option { // WithForm return form option func WithForm(form *hstate.Form) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + if o.Form == nil { o.Form = form } else if form != nil { @@ -249,6 +315,9 @@ func WithForm(form *hstate.Form) Option { // WithQuery return query parameters option func WithQuery(parameters url.Values) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + if o.Query == nil { o.Query = parameters } else { @@ -261,6 +330,9 @@ func WithQuery(parameters url.Values) Option { func WithLogger(logger logger.Logger) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Logger = logger } } @@ -268,6 +340,9 @@ func WithLogger(logger logger.Logger) Option { // WithQueryParameter return query parameter option func WithQueryParameter(name, value string) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + if o.Query == nil { o.Query = make(url.Values) } @@ -278,6 +353,9 @@ func WithQueryParameter(name, value string) Option { // WithHeader return header option func WithHeader(name, value string) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + if o.Header == nil { o.Header = make(http.Header) } @@ -288,6 +366,9 @@ func WithHeader(name, value string) Option { // WithHeaders return headers option func WithHeaders(header http.Header) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + if o.Header == nil { o.Header = header } @@ -300,6 +381,9 @@ func WithHeaders(header http.Header) Option { // WithMetrics return metrics option func WithMetrics(metrics response.Metrics) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Metrics = metrics } } @@ -307,6 +391,9 @@ func WithMetrics(metrics response.Metrics) Option { // WithResource return resource option func WithResource(resource *view.Resource) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Resource = resource } } @@ -314,6 +401,9 @@ func WithResource(resource *view.Resource) Option { // WithConstants return Constants option func WithConstants(constants map[string]interface{}) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Constants = constants } } @@ -321,6 +411,9 @@ func WithConstants(constants map[string]interface{}) Option { // WithTypes return types option func WithTypes(types ...*state.Type) Option { return func(o *Options) { + o.mu.Lock() + defer o.mu.Unlock() + o.Types = types } } From bf88275b1262b7f4357b0fc36f5d77db82dddd80 Mon Sep 17 00:00:00 2001 From: adranwit Date: Tue, 6 Jan 2026 08:12:11 -0800 Subject: [PATCH 114/117] patched marshaller --- go.mod | 2 +- go.sum | 137 +++++++++++---------------------------------------------- 2 files changed, 26 insertions(+), 113 deletions(-) diff --git a/go.mod b/go.mod index a5a9eab23..dc81b120e 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( require ( github.com/viant/govalidator v0.3.1 - github.com/viant/sqlparser v0.8.1 + github.com/viant/sqlparser v0.9.0 ) require ( diff --git a/go.sum b/go.sum index 38ca1e6c4..aafc7c00c 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,6 @@ cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFO cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= -cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= @@ -106,12 +104,8 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.2.0 h1:y6oTcpMSbOcXbwYgUUrvI+mrQ2xbrcdpPgtVbCGTLTk= -cloud.google.com/go/auth v0.2.0/go.mod h1:+yb+oy3/P0geX6DLKlqiGHARGR6EX2GRtYCzWOCQSbU= cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8= cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= -cloud.google.com/go/auth/oauth2adapt v0.2.0 h1:FR8zevgQwu+8CqiOT5r6xCmJa3pJC/wdXEEPF1OkNhA= -cloud.google.com/go/auth/oauth2adapt v0.2.0/go.mod h1:AfqujpDAlTfLfeCIl/HJZZlIxD8+nJoZ5e0x1IxGq5k= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -194,8 +188,6 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= @@ -293,8 +285,6 @@ cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLY cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8= -cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= cloud.google.com/go/firestore v1.17.0 h1:iEd1LBbkDZTFsLw3sTH50eyg4qe8eoG6CjocmEXO9aQ= cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y= cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= @@ -335,8 +325,6 @@ cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGE cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= -cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= @@ -368,11 +356,11 @@ cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6 cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/logging v1.11.0 h1:v3ktVzXMV7CwHq1MBF65wcqLMA7i+z3YxbUsoK7mOKs= +cloud.google.com/go/logging v1.11.0/go.mod h1:5LDiJC/RxTt+fHc1LAt20R9TKiUTReDg6RuuFOZ67+A= cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= -cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= -cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= @@ -508,8 +496,6 @@ cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISI cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY= -cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= cloud.google.com/go/secretmanager v1.14.1 h1:xlWSIg8rtBn5qCr2f3XtQP19+5COyf/ll49SEvi/0vM= cloud.google.com/go/secretmanager v1.14.1/go.mod h1:L+gO+u2JA9CCyXpSR8gDH0o8EV7i/f0jdBOrUXcIV0U= cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= @@ -567,8 +553,6 @@ cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeL cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= -cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= cloud.google.com/go/storage v1.45.0 h1:5av0QcIVj77t+44mV4gffFC/LscFRUhto6UBMB5SimM= cloud.google.com/go/storage v1.45.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= @@ -590,6 +574,8 @@ cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/trace v1.11.1 h1:UNqdP+HYYtnm6lb91aNA5JQ0X14GnxkABGlfz2PzPew= +cloud.google.com/go/trace v1.11.1/go.mod h1:IQKNQuBzH72EGaXEodKlNJrWykGZxet2zgjtS60OtjA= cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= @@ -654,6 +640,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.1 h1:oTX4vsorBZo/Zdum6OKPA4o7544hm6smoRv1QjpTwGo= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.1/go.mod h1:0wEl7vrAD8mehJyohS9HZy+WyEOaQO2mJx86Cvh93kM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 h1:8nn+rsCvTq9axyEh382S0PFLBeaFwNsT43IrPWzctRU= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= @@ -680,40 +668,26 @@ github.com/aws/aws-lambda-go v1.31.0/go.mod h1:IF5Q7wj4VyZyUFnZ54IQqeWtctHQ9tz+K github.com/aws/aws-sdk-go v1.51.23 h1:/3TEdsEE/aHmdKGw2NrOp7Sdea76zfffGkTTSXTsDxY= github.com/aws/aws-sdk-go v1.51.23/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.17.2/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= -github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= -github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA= -github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE= github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ= github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.26 h1:tsm8g/nJxi8+/7XyJJcP2dLrnK/5rkFp6+i2nhmz5fk= -github.com/aws/aws-sdk-go-v2/credentials v1.17.26/go.mod h1:3vAM49zkIa3q8WT6o9Ve5Z0vdByDMwmdScO0zvThTgI= github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7 h1:CyuByiiCA4lPfU8RaHJh2wIYYn0hkFlOkMfWkVY67Mc= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.10.7/go.mod h1:pAMtgCPVxcKohC/HNI6nLwLeW007eYl3T+pq7yTMV3o= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 h1:X+4YY5kZRI/cOoSMVMGTqFXHAMg1bvvay7IBcqHpybQ= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33/go.mod h1:DPynzu+cn92k5UQ6tZhX+wfTB4ah6QDU/NgdHqatmvk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26/go.mod h1:2E0LdbJW6lbeU4uxjum99GZzI0ZjDpAb0CoSCM0oeEY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20/go.mod h1:/+6lSiby8TBFpTVXZgKiN/rCfkYXEGvhlM4zCgPpt7w= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 h1:7edmS3VOBDhK00b/MwGtGglCm7hhwNYnjJs/PgFdMQE= @@ -723,16 +697,12 @@ github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.8/go.mod h1:jvXzk+hVrlkiQOvn github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27 h1:7MhqbR+k+b0gbOxp+W8yXgsl/Z5/dtMh85K0WI8X2EA= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.27/go.mod h1:wX9QEZJ8Dw1fdAKCOAUmSvAe3wNJFxnE/4AeYc8blGA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 h1:4FMHqLfk0efmTqhXVRL5xYRqlEBNBiRI7N6w4jsEdd4= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2/go.mod h1:LWoqeWlK9OZeJxsROW2RqrSPvQHKTpp69r/iDjwsSaw= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20 h1:kSZR22oLBDMtP8ZPGXhz649NU77xsJDG7g3xfT6nHVk= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.20/go.mod h1:lxM5qubwGNX29Qy+xTFG8G0r2Mj/TmyC+h3hS/7E4V8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt3E41huP+GvQZJD38WLsgVp4iOtAjg= @@ -747,21 +717,13 @@ github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 h1:Vjqy5BZCOIsn4Pj8xzyqgGmsSqzz github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3/go.mod h1:L0enV3GCRd5iG9B64W35C4/hwsCB00Ib+DKVGTadKHI= github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2 h1:z6Pq4+jtKlhK4wWJGHRGwMLGjC1HZwAO3KJr/Na0tSU= github.com/aws/aws-sdk-go-v2/service/ssm v1.55.2/go.mod h1:DSmu/VZzpQlAubWBbAvNpt+S4k/XweglJi4XaDGyvQk= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.3 h1:Fv1vD2L65Jnp5QRsdiM64JvUM4Xe+E0JyVsRQKv6IeA= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.3/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo= github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= -github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -772,7 +734,6 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -800,8 +761,8 @@ github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfT github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= @@ -821,8 +782,11 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs= github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= @@ -857,8 +821,6 @@ github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9 github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -939,8 +901,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gops v0.3.23 h1:OjsHRINl5FiIyTc8jivIg4UN0GY6Nh32SL8KRbl8GQo= @@ -950,8 +912,9 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -973,8 +936,6 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -986,8 +947,6 @@ github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= @@ -1006,8 +965,6 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= @@ -1045,8 +1002,9 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -1112,8 +1070,8 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1132,8 +1090,9 @@ github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTK github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= @@ -1183,8 +1142,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= @@ -1193,8 +1151,6 @@ github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d h1:IRmoMmrWqkHD github.com/viant/aerospike v0.2.11-0.20241108195857-ed524b97800d/go.mod h1:eRBywl0oTDM/oGhGLUeJjnC7XzmkTGuW9/og5YFy0K0= github.com/viant/afs v1.26.2 h1:rOs/iFxFlEndhIRATJVXlNWhVU0cGdRQAGVTVJPdsc0= github.com/viant/afs v1.26.2/go.mod h1:rScbFd9LJPGTM8HOI8Kjwee0AZ+MZMupAvFpPg+Qdj4= -github.com/viant/afsc v1.9.1 h1:BIus7fYyjM+MDgKuAzCBfoV4oVy2xTVhuFsQKUCPvkQ= -github.com/viant/afsc v1.9.1/go.mod h1:FA/xVjaMM10qGByabP8anTVMH6N4eUsAeWm5xcEZJJA= github.com/viant/afsc v1.16.0 h1:/kOH/flNwme6h3oFrU/KPnMHkhbCZxQncTf1GSQIlBQ= github.com/viant/afsc v1.16.0/go.mod h1:Z6fP3VcmzS8Sg2lowctR6KkVEX7XxJ8aNaoHqhUiZkY= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= @@ -1235,8 +1191,8 @@ github.com/viant/pgo v0.11.0 h1:PNuYVhwTfyrAHGBO6lxaMFuHP4NkjKV8ULecz3OWk8c= github.com/viant/pgo v0.11.0/go.mod h1:MFzHmkRFZlciugEgUvpl/3grK789PBSH4dUVSLOSo+Q= github.com/viant/scy v0.24.0 h1:KAC3IUARkQxTNSuwBK2YhVBJMOOLN30YaLKHbbuSkMU= github.com/viant/scy v0.24.0/go.mod h1:7uNRS67X45YN+JqTLCcMEhehffVjqrejULEDln9p0Ao= -github.com/viant/sqlparser v0.8.1 h1:nbcTecMtW7ROk5aNB5/BWUxnduepRPOkhVo9RWxI1Ns= -github.com/viant/sqlparser v0.8.1/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= +github.com/viant/sqlparser v0.9.0 h1:MoRJ18cm4MeSGLMNO8jZZzb1S5rLaIksEbdqE+8RBEw= +github.com/viant/sqlparser v0.9.0/go.mod h1:2QRGiGZYk2/pjhORGG1zLVQ9JO+bXFhqIVi31mkCRPg= github.com/viant/sqlx v0.21.0 h1:Lx5KXmzfSjSvZZX5P0Ua9kFGvAmCxAjLOPe9pQA7VmY= github.com/viant/sqlx v0.21.0/go.mod h1:woTOwNiqvt6SqkI+5nyzlixcRTTV0IvLZUTberqb8mo= github.com/viant/structology v0.8.0 h1:WKdK67l+O1eqsubn8PWMhWcgspUGJ22SgJxUMfiRgqE= @@ -1303,30 +1259,18 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= @@ -1354,8 +1298,6 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1420,8 +1362,6 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1493,8 +1433,6 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1530,8 +1468,6 @@ golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= @@ -1553,8 +1489,6 @@ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1648,8 +1582,6 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1667,8 +1599,7 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1689,8 +1620,6 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1700,8 +1629,6 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1768,8 +1695,6 @@ golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1780,12 +1705,12 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= @@ -1854,8 +1779,6 @@ google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjY google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.174.0 h1:zB1BWl7ocxfTea2aQ9mgdzXjnfPySllpPOskdnO+q34= -google.golang.org/api v0.174.0/go.mod h1:aC7tB6j0HR1Nl0ni5ghpx6iLasmAX78Zkh/wgxAAjLg= google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0= google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -2010,16 +1933,12 @@ google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= -google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= @@ -2027,8 +1946,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -2075,8 +1992,6 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -2098,8 +2013,6 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From f13d12830343bc5b8689923fd9c0b4721ca1b1df Mon Sep 17 00:00:00 2001 From: adranwit Date: Thu, 8 Jan 2026 15:14:23 -0800 Subject: [PATCH 115/117] patched marshaller --- view/tags/parameter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/tags/parameter.go b/view/tags/parameter.go index 7acd1c563..de777c815 100644 --- a/view/tags/parameter.go +++ b/view/tags/parameter.go @@ -88,7 +88,7 @@ func (p *Parameter) Tag() *tags.Tag { if *p.Cacheable { value = "true" } - appendNonEmpty(builder, "cachable", value) + appendNonEmpty(builder, "cacheable", value) } if p.Cardinality == "One" { From 0a05392fa97677d75d47087cf469de5e0b459b1d Mon Sep 17 00:00:00 2001 From: adranwit Date: Fri, 9 Jan 2026 12:27:55 -0800 Subject: [PATCH 116/117] patched marshaller --- gateway/router/marshal/json/marshaller_strings.go | 1 - 1 file changed, 1 deletion(-) diff --git a/gateway/router/marshal/json/marshaller_strings.go b/gateway/router/marshal/json/marshaller_strings.go index 2e20e16e0..b0ba6fcea 100644 --- a/gateway/router/marshal/json/marshaller_strings.go +++ b/gateway/router/marshal/json/marshaller_strings.go @@ -104,7 +104,6 @@ func marshallString(asString string, sb *MarshallSession, _ *strings.Replacer) { func getReplacer() *strings.Replacer { return strings.NewReplacer(`\`, `\\`, `"`, `\"`, - `/`, `\/`, "\b", `\b`, "\f", `\f`, "\n", `\n`, From 30a174e327ace3a6753fbc887b33abd810a3cd9b Mon Sep 17 00:00:00 2001 From: adranwit Date: Sun, 11 Jan 2026 15:22:57 -0800 Subject: [PATCH 117/117] fix oauth refresh issue --- gateway/mcp.go | 38 +++++++++++++++++++++++++++++++++----- mcp/server.go | 1 + 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/gateway/mcp.go b/gateway/mcp.go index e9687e45a..d8fe71a0c 100644 --- a/gateway/mcp.go +++ b/gateway/mcp.go @@ -17,6 +17,7 @@ import ( "github.com/viant/datly/view/state" "github.com/viant/jsonrpc" "github.com/viant/mcp-protocol/authorization" + oauthmeta "github.com/viant/mcp-protocol/oauth2/meta" "github.com/viant/mcp-protocol/schema" serverproto "github.com/viant/mcp-protocol/server" "github.com/viant/toolbox" @@ -112,6 +113,10 @@ func (r *Router) mcpToolCallHandler(component *repository.Component, aRoute *Rou rw := proxy.NewWriter() aRoute.Handle(rw, httpReq) + if rw.Code == http.StatusUnauthorized { + return nil, r.mcpUnauthorizedError() + } + // 5) Build tool result (text + structured on error) return r.buildToolCallResult(rw, finalURL, aRoute.Path.Method), nil } @@ -332,6 +337,26 @@ func (r *Router) addAuthTokenIfPresent(ctx context.Context, httpRequest *http.Re } } +const defaultMCPProtectedResource = "https://datly.viantinc.com" + +func (r *Router) mcpUnauthorizedError() *jsonrpc.Error { + if r == nil || r.config == nil || r.config.MCP == nil { + return jsonrpc.NewError(schema.Unauthorized, "Unauthorized", nil) + } + issuerURL := strings.TrimSpace(r.config.MCP.IssuerURL) + if issuerURL == "" { + return jsonrpc.NewError(schema.Unauthorized, "Unauthorized", nil) + } + return jsonrpc.NewError(schema.Unauthorized, "Unauthorized", &authorization.Authorization{ + RequiredScopes: []string{}, + UseIdToken: true, + ProtectedResourceMetadata: &oauthmeta.ProtectedResourceMetadata{ + Resource: defaultMCPProtectedResource, + AuthorizationServers: []string{issuerURL}, + }, + }) +} + func (r *Router) buildToolInputType(components *repository.Component) reflect.Type { var inputFields []reflect.StructField var uniqueQuery = make(map[string]bool) @@ -468,9 +493,9 @@ func (r *Router) buildTemplateResourceIntegration(item *dpath.Item, aPath *dpath func (r *Router) reactMcpResourceHandler(mcpResourceTemplate schema.ResourceTemplate, aRoute *Route, provider *repository.Provider) func(ctx context.Context, request *schema.ReadResourceRequest) (*schema.ReadResourceResult, *jsonrpc.Error) { handler := func(ctx context.Context, request *schema.ReadResourceRequest) (*schema.ReadResourceResult, *jsonrpc.Error) { - result, err := r.handleMcpRead(ctx, &request.Params, &mcpResourceTemplate, aRoute, provider) - if err != nil { - return nil, jsonrpc.NewInternalError(err.Error(), nil) + result, rpcErr := r.handleMcpRead(ctx, &request.Params, &mcpResourceTemplate, aRoute, provider) + if rpcErr != nil { + return nil, rpcErr } if len(result) == 0 { return &schema.ReadResourceResult{Contents: []schema.ReadResourceResultContentsElem{}}, nil @@ -532,12 +557,12 @@ func (r *Router) hasMcpResource(URI string) bool { return false } -func (r *Router) handleMcpRead(ctx context.Context, params *schema.ReadResourceRequestParams, template *schema.ResourceTemplate, aRoute *Route, provider *repository.Provider) ([]schema.ReadResourceResultContentsElem, error) { +func (r *Router) handleMcpRead(ctx context.Context, params *schema.ReadResourceRequestParams, template *schema.ResourceTemplate, aRoute *Route, provider *repository.Provider) ([]schema.ReadResourceResultContentsElem, *jsonrpc.Error) { URI := furl.Path(params.Uri) URL := fmt.Sprintf("http://localhost/%v", URI) // fallback to a local URL for now, this should be replaced with the actual service URL component, err := provider.Component(ctx) // ensure the provider is initialized if err != nil { - return nil, fmt.Errorf("failed to get component from provider: %w", err) + return nil, jsonrpc.NewInternalError(fmt.Errorf("failed to get component from provider: %w", err).Error(), nil) } byLoc := make(map[string]*state.Parameter) for _, param := range component.View.GetResource().Parameters { @@ -551,6 +576,9 @@ func (r *Router) handleMcpRead(ctx context.Context, params *schema.ReadResourceR } r.addAuthTokenIfPresent(ctx, httpRequest) aRoute.Handle(responseWriter, httpRequest) // route the request to the actual handler + if responseWriter.Code == http.StatusUnauthorized { + return nil, r.mcpUnauthorizedError() + } var result []schema.ReadResourceResultContentsElem mimeType := "" if template.MimeType != nil { diff --git a/mcp/server.go b/mcp/server.go index 2409a38ea..b3e1c3e45 100644 --- a/mcp/server.go +++ b/mcp/server.go @@ -57,6 +57,7 @@ func (s *Server) init() error { } if issuerURL == "" && oauth2Config != nil { issuerURL, _ = url.Base(oauth2Config.Endpoint.AuthURL, http.SecureScheme) + s.config.IssuerURL = issuerURL } } authPolicy := &authorization.Policy{