package preparation import ( "context" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/eventstore" ) // Validation of the input values of the command and if correct returns // the function to create commands or if not valid an error type Validation func() (CreateCommands, error) // CreateCommands builds the commands // the filter param is an extended version of the eventstore filter method // it filters for events including the commands on the current context type CreateCommands func(context.Context, FilterToQueryReducer) ([]eventstore.Command, error) // FilterToQueryReducer is an abstraction of the eventstore method type FilterToQueryReducer func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) var ( //ErrNotExecutable is thrown if no command creator was created ErrNotExecutable = errors.ThrowInvalidArgument(nil, "PREPA-pH70n", "Errors.Internal") ) // PrepareCommands checks the passed validations and if ok creates the commands func PrepareCommands(ctx context.Context, filter FilterToQueryReducer, validations ...Validation) (cmds []eventstore.Command, err error) { commanders, err := validate(validations) if err != nil { return nil, err } return create(ctx, filter, commanders) } func validate(validations []Validation) ([]CreateCommands, error) { creators := make([]CreateCommands, 0, len(validations)) for _, validate := range validations { cmds, err := validate() if err != nil { return nil, err } creators = append(creators, cmds) } if len(creators) == 0 { return nil, ErrNotExecutable } return creators, nil } func create(ctx context.Context, filter FilterToQueryReducer, commanders []CreateCommands) (cmds []eventstore.Command, err error) { for _, command := range commanders { cmd, err := command(ctx, transactionFilter(filter, cmds)) if err != nil { return nil, err } cmds = append(cmds, cmd...) } return cmds, nil } func transactionFilter(filter FilterToQueryReducer, commands []eventstore.Command) FilterToQueryReducer { return func(ctx context.Context, query *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) { events, err := filter(ctx, query) if err != nil { return nil, err } for _, command := range commands { event := command.(eventstore.Event) if !query.Matches(event, len(events)) { continue } events = append(events, event) } return events, nil } }