From 9bc75d43d9ffe6ccc5efca2d6836940abefad835 Mon Sep 17 00:00:00 2001 From: adlerhurst <27845747+adlerhurst@users.noreply.github.com> Date: Fri, 7 Mar 2025 07:26:32 +0100 Subject: [PATCH] alles en scheiss --- backend/cmd/configure/bla4/iterator.go | 70 ++++++++++++++++++ backend/cmd/configure/bla4/update_config7.go | 6 +- backend/cmd/configure/bla5/update_config8.go | 74 +++++++++++++++++++ .../database/dialect/postgres/config.go | 28 ++++++- internal/eventstore/handler/v2/state.go | 2 +- 5 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 backend/cmd/configure/bla4/iterator.go create mode 100644 backend/cmd/configure/bla5/update_config8.go diff --git a/backend/cmd/configure/bla4/iterator.go b/backend/cmd/configure/bla4/iterator.go new file mode 100644 index 0000000000..b5acca0dfb --- /dev/null +++ b/backend/cmd/configure/bla4/iterator.go @@ -0,0 +1,70 @@ +package bla4 + +import ( + "fmt" + "log/slog" + "reflect" + + "github.com/manifoldco/promptui" +) + +type Iterator interface { + // NextField returns the name of the next field to configure. + // If it returns an empty string, the configuration is complete. + NextField() string + // FinishAllowed returns true if the configuration is complete and the user can skip the remaining fields. + FinishAllowed() bool +} + +func fieldFunctionByIterator(l *slog.Logger, f *field) Configure { + if !f.value.Type().Implements(reflect.TypeFor[Iterator]()) { + return nil + } + + return func() (value any, err error) { + iter := f.value.Interface().(Iterator) + sub := f.sub() + for { + fieldName := iter.NextField() + if fieldName == "" { + break + } + if iter.FinishAllowed() { + prompt := promptui.Prompt{ + Label: fmt.Sprintf("Finish configuration of %s", f.info.Name), + IsConfirm: true, + } + _, err := prompt.Run() + if err == nil { + break + } + } + info, ok := f.value.Type().FieldByName(fieldName) + if !ok { + return nil, fmt.Errorf("field %s not found", fieldName) + } + tag, err := newTag(info, f.value.FieldByName(fieldName)) + if err != nil { + return nil, err + } + if tag.skip { + continue + } + + res, err := fieldFunction( + l.With(slog.String("field", fieldName)), + &field{ + info: info, + viper: sub, //TODO: sub of sub + tag: tag, + }, + )() + if err != nil { + return nil, err + } + reflect.Indirect(f.value).FieldByName(fieldName).Set(reflect.ValueOf(res)) + } + f.viper.Set(f.tag.fieldName, sub.AllSettings()) + return value, err + } +} diff --git a/backend/cmd/configure/bla4/update_config7.go b/backend/cmd/configure/bla4/update_config7.go index 57ca00bb2d..7479a26171 100644 --- a/backend/cmd/configure/bla4/update_config7.go +++ b/backend/cmd/configure/bla4/update_config7.go @@ -88,7 +88,8 @@ func structToConfigureMap(l *slog.Logger, v *viper.Viper, object reflect.Value) func fieldFunction(l *slog.Logger, f *field) (configure Configure) { for _, mapper := range []func(*slog.Logger, *field) Configure{ - fieldFunctionByImplementation, + fieldFunctionByConfigurer, + fieldFunctionByIterator, fieldFunctionByReflection, } { if configure = mapper(l, f); configure != nil { @@ -98,9 +99,8 @@ func fieldFunction(l *slog.Logger, f *field) (configure Configure) { panic(fmt.Sprintf("unsupported field type: %s", f.info.Type.String())) } -func fieldFunctionByImplementation(l *slog.Logger, f *field) Configure { +func fieldFunctionByConfigurer(l *slog.Logger, f *field) Configure { if f.value.Type().Implements(reflect.TypeFor[Configurer]()) { - l.Debug("field is a custom implementation") return func() (value any, err error) { f.printStructInfo() res, err := f.value.Interface().(Configurer).Configure() diff --git a/backend/cmd/configure/bla5/update_config8.go b/backend/cmd/configure/bla5/update_config8.go new file mode 100644 index 0000000000..c2b033dccc --- /dev/null +++ b/backend/cmd/configure/bla5/update_config8.go @@ -0,0 +1,74 @@ +package bla5 + +import ( + "log/slog" + "os" + "reflect" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var Logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + AddSource: true, + Level: slog.LevelDebug, +})) + +type Configure func() (value any, err error) + +type Configurer interface { + // 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. + Configure() (value any, err error) +} + +func Update(v *viper.Viper, config any) func(cmd *cobra.Command, args []string) { + return func(cmd *cobra.Command, args []string) { + value := reflect.ValueOf(config) + structConfigures := structToConfigureMap(Logger, v, value) + for key, configure := range structConfigures { + result, err := configure() + if err != nil { + Logger.Error("error configuring field", slog.String("field", key), slog.Any("cause", err)) + return + } + value.Elem().FieldByName(key).Set(reflect.ValueOf(result)) + } + + err := v.WriteConfig() + if err != nil { + Logger.Error("error writing config", slog.Any("cause", err)) + os.Exit(1) + } + } +} + +func objectToFlow(l *slog.Logger, value reflect.Value) { + if value.Kind() == reflect.Pointer { + if value.IsNil() { + value = reflect.New(value.Type().Elem()) + } + value = value.Elem() + } + + typeOfValue := value.Type() + for i := 0; i < value.NumField(); i++ { + fieldValue := value.Field(i) + fieldType := typeOfValue.Field(i) + + l.Info("Processing field", slog.String("field", fieldType.Name)) + } +} + +type field struct { + set func(value reflect.Value) error +} + +type structField struct { + name string + + fields []field +} + +type primitiveField struct { +} diff --git a/backend/storage/database/dialect/postgres/config.go b/backend/storage/database/dialect/postgres/config.go index e5ee319f58..c0239f4fde 100644 --- a/backend/storage/database/dialect/postgres/config.go +++ b/backend/storage/database/dialect/postgres/config.go @@ -10,6 +10,7 @@ import ( "github.com/manifoldco/promptui" "github.com/mitchellh/mapstructure" + "github.com/zitadel/zitadel/backend/cmd/configure/bla4" "github.com/zitadel/zitadel/backend/storage/database" ) @@ -24,19 +25,38 @@ type Config struct { // Host string // Port int32 // Database string - // EventPushConnRatio float64 // MaxOpenConns uint32 // MaxIdleConns uint32 // MaxConnLifetime time.Duration // MaxConnIdleTime time.Duration // User User - // Admin AdminUser // // Additional options to be appended as options= // // The value will be taken as is. Multiple options are space separated. // Options string + + configuredFields []string } -// Configure implements bla3.Custom. +// FinishAllowed implements [bla4.Iterator]. +func (c *Config) FinishAllowed() bool { + // Option can be skipped + return len(c.configuredFields) < 2 +} + +// NextField implements [bla4.Iterator]. +func (c *Config) NextField() string { + if c.configuredFields == nil { + c.configuredFields = []string{"Host", "Port", "Database", "MaxOpenConns", "MaxIdleConns", "MaxConnLifetime", "MaxConnIdleTime", "User", "Options"} + } + if len(c.configuredFields) == 0 { + return "" + } + field := c.configuredFields[0] + c.configuredFields = c.configuredFields[1:] + return field +} + +// Configure implements [bla4.Configurer]. func (c *Config) Configure() (value any, err error) { typeSelect := promptui.Select{ Label: "Configure the database connection", @@ -67,6 +87,8 @@ func (c *Config) Configure() (value any, err error) { return prompt.Run() } +var _ bla4.Iterator = (*Config)(nil) + // Connect implements [database.Connector]. func (c *Config) Connect(ctx context.Context) (database.Pool, error) { pool, err := pgxpool.NewWithConfig(ctx, c.config) diff --git a/internal/eventstore/handler/v2/state.go b/internal/eventstore/handler/v2/state.go index d3b6953488..b81719ca55 100644 --- a/internal/eventstore/handler/v2/state.go +++ b/internal/eventstore/handler/v2/state.go @@ -54,7 +54,7 @@ func (h *Handler) currentState(ctx context.Context, tx *sql.Tx, config *triggerC stateQuery = currentStateAwaitStmt } - row := tx.QueryRow(stateQuery, currentState.instanceID, h.projection.Name()) + row := tx.QueryRowContext(ctx, stateQuery, currentState.instanceID, h.projection.Name()) err = row.Scan( aggregateID, aggregateType,