try chain

This commit is contained in:
adlerhurst
2025-03-12 10:01:47 +01:00
parent 9bc75d43d9
commit 01499d77c7
6 changed files with 176 additions and 91 deletions

View File

@@ -0,0 +1 @@
package bla5

View File

@@ -3,7 +3,6 @@ package bla5
import ( import (
"log/slog" "log/slog"
"os" "os"
"reflect"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@@ -16,6 +15,8 @@ var Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
type Configure func() (value any, err error) type Configure func() (value any, err error)
// Configurer should be implemented by each field of the configuration struct.
// It is used to configure the value of the field.
type Configurer interface { type Configurer interface {
// Configure is called to configure the value. // Configure is called to configure the value.
// It must return the same type as itself. Otherwise [Update] will panic because it is not able to set the value. // It must return the same type as itself. Otherwise [Update] will panic because it is not able to set the value.
@@ -24,51 +25,51 @@ type Configurer interface {
func Update(v *viper.Viper, config any) func(cmd *cobra.Command, args []string) { func Update(v *viper.Viper, config any) func(cmd *cobra.Command, args []string) {
return func(cmd *cobra.Command, args []string) { return func(cmd *cobra.Command, args []string) {
value := reflect.ValueOf(config) // value := reflect.ValueOf(config)
structConfigures := structToConfigureMap(Logger, v, value) // structConfigures := structToConfigureMap(Logger, v, value)
for key, configure := range structConfigures { // for key, configure := range structConfigures {
result, err := configure() // result, err := configure()
if err != nil { // if err != nil {
Logger.Error("error configuring field", slog.String("field", key), slog.Any("cause", err)) // Logger.Error("error configuring field", slog.String("field", key), slog.Any("cause", err))
return // return
} // }
value.Elem().FieldByName(key).Set(reflect.ValueOf(result)) // value.Elem().FieldByName(key).Set(reflect.ValueOf(result))
} // }
err := v.WriteConfig() // err := v.WriteConfig()
if err != nil { // if err != nil {
Logger.Error("error writing config", slog.Any("cause", err)) // Logger.Error("error writing config", slog.Any("cause", err))
os.Exit(1) // os.Exit(1)
} // }
} }
} }
func objectToFlow(l *slog.Logger, value reflect.Value) { // func objectToFlow(l *slog.Logger, value reflect.Value) {
if value.Kind() == reflect.Pointer { // if value.Kind() == reflect.Pointer {
if value.IsNil() { // if value.IsNil() {
value = reflect.New(value.Type().Elem()) // value = reflect.New(value.Type().Elem())
} // }
value = value.Elem() // value = value.Elem()
} // }
typeOfValue := value.Type() // typeOfValue := value.Type()
for i := 0; i < value.NumField(); i++ { // for i := 0; i < value.NumField(); i++ {
fieldValue := value.Field(i) // fieldValue := value.Field(i)
fieldType := typeOfValue.Field(i) // fieldType := typeOfValue.Field(i)
l.Info("Processing field", slog.String("field", fieldType.Name)) // l.Info("Processing field", slog.String("field", fieldType.Name))
} // }
} // }
type field struct { // type field struct {
set func(value reflect.Value) error // set func(value reflect.Value) error
} // }
type structField struct { // type structField struct {
name string // name string
fields []field // fields []field
} // }
type primitiveField struct { // type primitiveField struct {
} // }

View File

@@ -4,18 +4,50 @@ import (
"context" "context"
"github.com/zitadel/zitadel/backend/repository" "github.com/zitadel/zitadel/backend/repository"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/telemetry/logging"
"github.com/zitadel/zitadel/backend/telemetry/tracing"
) )
type InstanceBuilder struct { // type Middleware[O any, H Handler[O]] interface {
tracer *tracing.Tracer // New() H
logger *logging.Logger // NewWithNext(next Handler[O]) H
// }
type Middleware[Req, Res any] interface {
New() Handler[Req, Res]
NewWithNext(next Handler[Req, Res]) Handler[Req, Res]
} }
func (f *InstanceBuilder) BuildSetUpInstance(tx database.Transaction) func(ctx context.Context, instance *repository.Instance) error { type Handler[Req, Res any] interface {
return func(ctx context.Context, instance *repository.Instance) error { Handle(ctx context.Context, request Req) (Res, error)
return tx.Exec(ctx, "INSERT INTO instances (id, name) VALUES ($1, $2)", instance.ID, instance.Name) SetNext(next Handler[Req, Res])
Name() string
} }
// type InstanceBuilder struct {
// tracer *traced.Instance
// logger *logged.Instance
// cache *cache.Instance
// events *event.Instance
// db *sql.Instance
// }
type InstanceSetUpBuilder struct {
tracer Middleware[*repository.Instance, *repository.Instance]
logger Middleware[*repository.Instance, *repository.Instance]
cache Middleware[*repository.Instance, *repository.Instance]
events Middleware[*repository.Instance, *repository.Instance]
db Middleware[*repository.Instance, *repository.Instance]
}
func (i *InstanceSetUpBuilder) Build() {
instance := i.tracer.NewWithNext(
i.logger.NewWithNext(
i.db.NewWithNext(
i.events.NewWithNext(
i.cache.New(),
),
),
),
)
_ = instance
// instance.
} }

View File

@@ -0,0 +1,55 @@
package traced
import (
"context"
"github.com/zitadel/zitadel/backend/domain/factory"
"github.com/zitadel/zitadel/backend/telemetry/tracing"
)
type Tracer[Req, Res any] struct {
tracing.Tracer
next factory.Handler[Req, Res]
}
func (*Tracer[Req, Res]) Name() string {
return "Tracer"
}
// Handle implements [factory.Handler].
func (t *Tracer[Req, Res]) Handle(ctx context.Context, request Req) (res Res, err error) {
if t.next == nil {
return res, nil
}
ctx, span := t.Tracer.Start(
ctx,
t.next.Name(),
)
defer func() {
if err != nil {
span.RecordError(err)
}
span.End()
}()
return t.next.Handle(ctx, request)
}
// SetNext implements [factory.Handler].
func (t *Tracer[Req, Res]) SetNext(next factory.Handler[Req, Res]) {
t.next = next
}
// New implements [factory.Middleware].
func (t *Tracer[Req, Res]) New() factory.Handler[Req, Res] {
return t.NewWithNext(nil)
}
// NewWithNext implements [factory.Middleware].
func (t *Tracer[Req, Res]) NewWithNext(next factory.Handler[Req, Res]) factory.Handler[Req, Res] {
return &Tracer[Req, Res]{Tracer: t.Tracer, next: next}
}
var (
_ factory.Middleware[any, any] = (*Tracer[any, any])(nil)
_ factory.Handler[any, any] = (*Tracer[any, any])(nil)
)

View File

@@ -2,11 +2,9 @@ package database
import ( import (
"context" "context"
"github.com/zitadel/zitadel/backend/cmd/configure/bla4"
) )
type Connector interface { type Connector interface {
Connect(ctx context.Context) (Pool, error) Connect(ctx context.Context) (Pool, error)
bla4.Configurer // bla4.Configurer
} }

View File

@@ -5,11 +5,9 @@ import (
"errors" "errors"
"reflect" "reflect"
"github.com/manifoldco/promptui"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/zitadel/zitadel/backend/cmd/configure/bla4"
"github.com/zitadel/zitadel/backend/storage/database" "github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/storage/database/dialect/postgres" "github.com/zitadel/zitadel/backend/storage/database/dialect/postgres"
) )
@@ -43,47 +41,47 @@ type Config struct {
} }
// Configure implements [configure.Configurer]. // Configure implements [configure.Configurer].
func (c *Config) Configure() (any, error) { // func (c *Config) Configure() (any, error) {
possibilities := make([]string, len(hooks)) // possibilities := make([]string, len(hooks))
var cursor int // var cursor int
for i, hook := range hooks { // for i, hook := range hooks {
if _, ok := c.Dialects[hook.Name]; ok { // if _, ok := c.Dialects[hook.Name]; ok {
cursor = i // cursor = i
} // }
possibilities[i] = hook.Name // possibilities[i] = hook.Name
} // }
prompt := promptui.Select{ // prompt := promptui.Select{
Label: "Select a dialect", // Label: "Select a dialect",
Items: possibilities, // Items: possibilities,
CursorPos: cursor, // CursorPos: cursor,
} // }
i, _, err := prompt.Run() // i, _, err := prompt.Run()
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
var config bla4.Configurer // var config bla4.Configurer
if dialect, ok := c.Dialects[hooks[i].Name]; ok { // if dialect, ok := c.Dialects[hooks[i].Name]; ok {
config, err = hooks[i].Decode(dialect) // config, err = hooks[i].Decode(dialect)
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
} else { // } else {
clear(c.Dialects) // clear(c.Dialects)
config = hooks[i].Constructor() // config = hooks[i].Constructor()
} // }
if c.Dialects == nil { // if c.Dialects == nil {
c.Dialects = make(map[string]any) // c.Dialects = make(map[string]any)
} // }
c.Dialects[hooks[i].Name], err = config.Configure() // c.Dialects[hooks[i].Name], err = config.Configure()
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
return c, nil // return c, nil
} // }
func (c Config) Connect(ctx context.Context) (database.Pool, error) { func (c Config) Connect(ctx context.Context) (database.Pool, error) {
if len(c.Dialects) != 1 { if len(c.Dialects) != 1 {