diff --git a/.releaserc.js b/.releaserc.js index b8d5a8551a..f24249cada 100644 --- a/.releaserc.js +++ b/.releaserc.js @@ -1,7 +1,7 @@ module.exports = { branches: [ - {name: 'main', channel: 'next'}, - {name: 'next', prerelease: true} + {name: 'main'}, + {name: 'next'}, ], plugins: [ "@semantic-release/commit-analyzer" diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 85d6c0ab15..1acbb55d44 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -398,6 +398,7 @@ Quotas: Eventstore: PushTimeout: 15s + AllowOrderByCreationDate: false DefaultInstance: InstanceName: diff --git a/cmd/start/start.go b/cmd/start/start.go index 90362d61e9..e0829b7eb3 100644 --- a/cmd/start/start.go +++ b/cmd/start/start.go @@ -115,7 +115,7 @@ func startZitadel(config *Config, masterKey string) error { return fmt.Errorf("cannot start queries: %w", err) } - authZRepo, err := authz.Start(queries, dbClient, keys.OIDC, config.ExternalSecure) + authZRepo, err := authz.Start(queries, dbClient, keys.OIDC, config.ExternalSecure, config.Eventstore.AllowOrderByCreationDate) if err != nil { return fmt.Errorf("error starting authz repo: %w", err) } @@ -229,11 +229,11 @@ func startAPIs( if err != nil { return fmt.Errorf("error creating api %w", err) } - authRepo, err := auth_es.Start(ctx, config.Auth, config.SystemDefaults, commands, queries, dbClient, eventstore, keys.OIDC, keys.User) + authRepo, err := auth_es.Start(ctx, config.Auth, config.SystemDefaults, commands, queries, dbClient, eventstore, keys.OIDC, keys.User, config.Eventstore.AllowOrderByCreationDate) if err != nil { return fmt.Errorf("error starting auth repo: %w", err) } - adminRepo, err := admin_es.Start(ctx, config.Admin, store, dbClient, eventstore) + adminRepo, err := admin_es.Start(ctx, config.Admin, store, dbClient, eventstore, config.Eventstore.AllowOrderByCreationDate) if err != nil { return fmt.Errorf("error starting admin repo: %w", err) } diff --git a/internal/admin/repository/eventsourcing/repository.go b/internal/admin/repository/eventsourcing/repository.go index d7c03c1fc9..febc2629de 100644 --- a/internal/admin/repository/eventsourcing/repository.go +++ b/internal/admin/repository/eventsourcing/repository.go @@ -23,8 +23,8 @@ type EsRepository struct { eventstore.AdministratorRepo } -func Start(ctx context.Context, conf Config, static static.Storage, dbClient *database.DB, esV2 *eventstore2.Eventstore) (*EsRepository, error) { - es, err := v1.Start(dbClient) +func Start(ctx context.Context, conf Config, static static.Storage, dbClient *database.DB, esV2 *eventstore2.Eventstore, allowOrderByCreationDate bool) (*EsRepository, error) { + es, err := v1.Start(dbClient, allowOrderByCreationDate) if err != nil { return nil, err } diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index 852ebcca91..454daffd11 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -34,8 +34,8 @@ type EsRepository struct { eventstore.OrgRepository } -func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *database.DB, esV2 *eventstore2.Eventstore, oidcEncryption crypto.EncryptionAlgorithm, userEncryption crypto.EncryptionAlgorithm) (*EsRepository, error) { - es, err := v1.Start(dbClient) +func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *database.DB, esV2 *eventstore2.Eventstore, oidcEncryption crypto.EncryptionAlgorithm, userEncryption crypto.EncryptionAlgorithm, allowOrderByCreationDate bool) (*EsRepository, error) { + es, err := v1.Start(dbClient, allowOrderByCreationDate) if err != nil { return nil, err } diff --git a/internal/authz/authz.go b/internal/authz/authz.go index f8f21e4125..6106d8a4e5 100644 --- a/internal/authz/authz.go +++ b/internal/authz/authz.go @@ -8,6 +8,6 @@ import ( "github.com/zitadel/zitadel/internal/query" ) -func Start(queries *query.Queries, dbClient *database.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure bool) (repository.Repository, error) { - return eventsourcing.Start(queries, dbClient, keyEncryptionAlgorithm, externalSecure) +func Start(queries *query.Queries, dbClient *database.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure, allowOrderByCreationDate bool) (repository.Repository, error) { + return eventsourcing.Start(queries, dbClient, keyEncryptionAlgorithm, externalSecure, allowOrderByCreationDate) } diff --git a/internal/authz/repository/eventsourcing/repository.go b/internal/authz/repository/eventsourcing/repository.go index c3f212d96c..2df593f11d 100644 --- a/internal/authz/repository/eventsourcing/repository.go +++ b/internal/authz/repository/eventsourcing/repository.go @@ -18,8 +18,8 @@ type EsRepository struct { eventstore.TokenVerifierRepo } -func Start(queries *query.Queries, dbClient *database.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure bool) (repository.Repository, error) { - es, err := v1.Start(dbClient) +func Start(queries *query.Queries, dbClient *database.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure, allowOrderByCreationDate bool) (repository.Repository, error) { + es, err := v1.Start(dbClient, allowOrderByCreationDate) if err != nil { return nil, err } diff --git a/internal/eventstore/config.go b/internal/eventstore/config.go index c9d00da267..21011dea67 100644 --- a/internal/eventstore/config.go +++ b/internal/eventstore/config.go @@ -9,8 +9,9 @@ import ( ) type Config struct { - PushTimeout time.Duration - Client *database.DB + PushTimeout time.Duration + Client *database.DB + AllowOrderByCreationDate bool repo repository.Repository } @@ -20,6 +21,6 @@ func TestConfig(repo repository.Repository) *Config { } func Start(config *Config) (*Eventstore, error) { - config.repo = z_sql.NewCRDB(config.Client) + config.repo = z_sql.NewCRDB(config.Client, config.AllowOrderByCreationDate) return NewEventstore(config), nil } diff --git a/internal/eventstore/repository/sql/crdb.go b/internal/eventstore/repository/sql/crdb.go index f78f210a6a..f27936de4c 100644 --- a/internal/eventstore/repository/sql/crdb.go +++ b/internal/eventstore/repository/sql/crdb.go @@ -99,10 +99,11 @@ const ( type CRDB struct { *database.DB + AllowOrderByCreationDate bool } -func NewCRDB(client *database.DB) *CRDB { - return &CRDB{client} +func NewCRDB(client *database.DB, allowOrderByCreationDate bool) *CRDB { + return &CRDB{client, allowOrderByCreationDate} } func (db *CRDB) Health(ctx context.Context) error { return db.Ping() } @@ -254,11 +255,19 @@ func (db *CRDB) db() *sql.DB { } func (db *CRDB) orderByEventSequence(desc bool) string { - if desc { - return " ORDER BY creation_date DESC, event_sequence DESC" + if db.AllowOrderByCreationDate { + if desc { + return " ORDER BY creation_date DESC, event_sequence DESC" + } + + return " ORDER BY creation_date, event_sequence" } - return " ORDER BY creation_date, event_sequence" + if desc { + return " ORDER BY event_sequence DESC" + } + + return " ORDER BY event_sequence" } func (db *CRDB) eventQuery() string { diff --git a/internal/eventstore/repository/sql/query_test.go b/internal/eventstore/repository/sql/query_test.go index 9560ff0918..af9aa9860c 100644 --- a/internal/eventstore/repository/sql/query_test.go +++ b/internal/eventstore/repository/sql/query_test.go @@ -542,6 +542,7 @@ func Test_query_events_with_crdb(t *testing.T) { DB: tt.fields.client, Database: new(testDB), }, + AllowOrderByCreationDate: true, } // setup initial data for query @@ -820,9 +821,12 @@ func Test_query_events_mocked(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - crdb := &CRDB{DB: &database.DB{ - Database: new(testDB), - }} + crdb := &CRDB{ + DB: &database.DB{ + Database: new(testDB), + }, + AllowOrderByCreationDate: true, + } if tt.fields.mock != nil { crdb.DB.DB = tt.fields.mock.client } diff --git a/internal/eventstore/v1/eventstore.go b/internal/eventstore/v1/eventstore.go index 0fc311f2e4..49e0910c73 100644 --- a/internal/eventstore/v1/eventstore.go +++ b/internal/eventstore/v1/eventstore.go @@ -22,9 +22,9 @@ type eventstore struct { repo repository.Repository } -func Start(db *database.DB) (Eventstore, error) { +func Start(db *database.DB, allowOrderByCreationDate bool) (Eventstore, error) { return &eventstore{ - repo: z_sql.Start(db), + repo: z_sql.Start(db, allowOrderByCreationDate), }, nil } diff --git a/internal/eventstore/v1/internal/repository/sql/config.go b/internal/eventstore/v1/internal/repository/sql/config.go index bef2df0de2..5ea34e6e40 100644 --- a/internal/eventstore/v1/internal/repository/sql/config.go +++ b/internal/eventstore/v1/internal/repository/sql/config.go @@ -4,8 +4,9 @@ import ( "github.com/zitadel/zitadel/internal/database" ) -func Start(client *database.DB) *SQL { +func Start(client *database.DB, allowOrderByCreationDate bool) *SQL { return &SQL{ - client: client, + client: client, + allowOrderByCreationDate: allowOrderByCreationDate, } } diff --git a/internal/eventstore/v1/internal/repository/sql/filter.go b/internal/eventstore/v1/internal/repository/sql/filter.go index 5674972de6..ab67730b59 100644 --- a/internal/eventstore/v1/internal/repository/sql/filter.go +++ b/internal/eventstore/v1/internal/repository/sql/filter.go @@ -21,11 +21,11 @@ func (db *SQL) Filter(ctx context.Context, searchQuery *es_models.SearchQueryFac if !searchQuery.InstanceFiltered { logging.WithFields("stack", string(debug.Stack())).Warn("instanceid not filtered") } - return filter(ctx, db.client, searchQuery) + return db.filter(ctx, db.client, searchQuery) } -func filter(ctx context.Context, db *database.DB, searchQuery *es_models.SearchQueryFactory) (events []*es_models.Event, err error) { - query, limit, values, rowScanner := buildQuery(ctx, db, searchQuery) +func (sql *SQL) filter(ctx context.Context, db *database.DB, searchQuery *es_models.SearchQueryFactory) (events []*es_models.Event, err error) { + query, limit, values, rowScanner := sql.buildQuery(ctx, db, searchQuery) if query == "" { return nil, errors.ThrowInvalidArgument(nil, "SQL-rWeBw", "invalid query factory") } @@ -53,7 +53,7 @@ func filter(ctx context.Context, db *database.DB, searchQuery *es_models.SearchQ } func (db *SQL) LatestSequence(ctx context.Context, queryFactory *es_models.SearchQueryFactory) (uint64, error) { - query, _, values, rowScanner := buildQuery(ctx, db.client, queryFactory) + query, _, values, rowScanner := db.buildQuery(ctx, db.client, queryFactory) if query == "" { return 0, errors.ThrowInvalidArgument(nil, "SQL-rWeBw", "invalid query factory") } @@ -68,7 +68,7 @@ func (db *SQL) LatestSequence(ctx context.Context, queryFactory *es_models.Searc } func (db *SQL) InstanceIDs(ctx context.Context, queryFactory *es_models.SearchQueryFactory) ([]string, error) { - query, _, values, rowScanner := buildQuery(ctx, db.client, queryFactory) + query, _, values, rowScanner := db.buildQuery(ctx, db.client, queryFactory) if query == "" { return nil, errors.ThrowInvalidArgument(nil, "SQL-Sfwg2", "invalid query factory") } diff --git a/internal/eventstore/v1/internal/repository/sql/filter_test.go b/internal/eventstore/v1/internal/repository/sql/filter_test.go index df352a236a..75863fed8a 100644 --- a/internal/eventstore/v1/internal/repository/sql/filter_test.go +++ b/internal/eventstore/v1/internal/repository/sql/filter_test.go @@ -123,7 +123,8 @@ func TestSQL_Filter(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sql := &SQL{ - client: &database.DB{DB: tt.fields.client.sqlClient, Database: new(testDB)}, + client: &database.DB{DB: tt.fields.client.sqlClient, Database: new(testDB)}, + allowOrderByCreationDate: true, } events, err := sql.Filter(context.Background(), tt.args.searchQuery) if (err != nil) != tt.res.wantErr { diff --git a/internal/eventstore/v1/internal/repository/sql/query.go b/internal/eventstore/v1/internal/repository/sql/query.go index ed4510e7f7..8b2ea1dc98 100644 --- a/internal/eventstore/v1/internal/repository/sql/query.go +++ b/internal/eventstore/v1/internal/repository/sql/query.go @@ -33,7 +33,7 @@ const ( " FROM eventstore.events" ) -func buildQuery(ctx context.Context, db dialect.Database, queryFactory *es_models.SearchQueryFactory) (query string, limit uint64, values []interface{}, rowScanner func(s scan, dest interface{}) error) { +func (sql *SQL) buildQuery(ctx context.Context, db dialect.Database, queryFactory *es_models.SearchQueryFactory) (query string, limit uint64, values []interface{}, rowScanner func(s scan, dest interface{}) error) { searchQuery, err := queryFactory.Build() if err != nil { logging.New().WithError(err).Warn("search query factory invalid") @@ -51,9 +51,17 @@ func buildQuery(ctx context.Context, db dialect.Database, queryFactory *es_model query += where if searchQuery.Columns == es_models.Columns_Event { - order := " ORDER BY creation_date, event_sequence" - if searchQuery.Desc { - order = " ORDER BY creation_date DESC, event_sequence DESC" + var order string + if sql.allowOrderByCreationDate { + order = " ORDER BY creation_date, event_sequence" + if searchQuery.Desc { + order = " ORDER BY creation_date DESC, event_sequence DESC" + } + } else { + order = " ORDER BY event_sequence" + if searchQuery.Desc { + order = " ORDER BY event_sequence DESC" + } } query += order } diff --git a/internal/eventstore/v1/internal/repository/sql/query_test.go b/internal/eventstore/v1/internal/repository/sql/query_test.go index f0b13bc701..0c4b4d9db9 100644 --- a/internal/eventstore/v1/internal/repository/sql/query_test.go +++ b/internal/eventstore/v1/internal/repository/sql/query_test.go @@ -470,7 +470,7 @@ func Test_buildQuery(t *testing.T) { ctx := context.Background() db := new(testDB) t.Run(tt.name, func(t *testing.T) { - gotQuery, gotLimit, gotValues, gotRowScanner := buildQuery(ctx, db, tt.args.queryFactory) + gotQuery, gotLimit, gotValues, gotRowScanner := (&SQL{allowOrderByCreationDate: true}).buildQuery(ctx, db, tt.args.queryFactory) if gotQuery != tt.res.query { t.Errorf("buildQuery() gotQuery = %v, want %v", gotQuery, tt.res.query) } diff --git a/internal/eventstore/v1/internal/repository/sql/sql.go b/internal/eventstore/v1/internal/repository/sql/sql.go index 3f5ecc431e..ab4c9ca26c 100644 --- a/internal/eventstore/v1/internal/repository/sql/sql.go +++ b/internal/eventstore/v1/internal/repository/sql/sql.go @@ -7,7 +7,8 @@ import ( ) type SQL struct { - client *database.DB + client *database.DB + allowOrderByCreationDate bool } func (db *SQL) Health(ctx context.Context) error {