refactor(query): use new packages for org by id query (#7826)

If the feature is enabled the new packages are used to query org by id

Part of: https://github.com/zitadel/zitadel/issues/7639

### Definition of Ready

- [x] I am happy with the code
- [x] Short description of the feature/issue is added in the pr
description
- [x] PR is linked to the corresponding user story
- [ ] Acceptance criteria are met
- [ ] All open todos and follow ups are defined in a new ticket and
justified
- [ ] Deviations from the acceptance criteria and design are agreed with
the PO and documented.
- [x] No debug or dead code
- [x] My code has no repetitions
- [ ] Critical parts are tested automatically
- [ ] Where possible E2E tests are implemented
- [ ] Documentation/examples are up-to-date
- [ ] All non-functional requirements are met
- [x] Functionality of the acceptance criteria is checked manually on
the dev system.
This commit is contained in:
Silvan 2024-05-24 13:32:57 +02:00 committed by GitHub
parent e58869c090
commit 0bfcf2c317
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 587 additions and 104 deletions

View File

@ -5,6 +5,7 @@ on:
jobs:
test:
timeout-minutes: 10
strategy:
fail-fast: false
matrix:

View File

@ -16,6 +16,7 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) *command.
UserSchema: req.UserSchema,
Actions: req.Actions,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
}
}
@ -28,6 +29,7 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
}
}
@ -39,6 +41,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
Actions: req.Actions,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
}
}
@ -51,6 +54,14 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
Actions: featureSourceToFlagPb(&f.Actions),
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
}
}
func featureSourceToImprovedPerformanceFlagPb(fs *query.FeatureSource[[]feature.ImprovedPerformanceType]) *feature_pb.ImprovedPerformanceFeatureFlag {
return &feature_pb.ImprovedPerformanceFeatureFlag{
ExecutionPaths: improvedPerformanceTypesToPb(fs.Value),
Source: featureLevelToSourcePb(fs.Level),
}
}
@ -81,3 +92,48 @@ func featureLevelToSourcePb(level feature.Level) feature_pb.Source {
return feature_pb.Source(level)
}
}
func improvedPerformanceTypesToPb(types []feature.ImprovedPerformanceType) []feature_pb.ImprovedPerformance {
res := make([]feature_pb.ImprovedPerformance, len(types))
for i, typ := range types {
res[i] = improvedPerformanceTypeToPb(typ)
}
return res
}
func improvedPerformanceTypeToPb(typ feature.ImprovedPerformanceType) feature_pb.ImprovedPerformance {
switch typ {
case feature.ImprovedPerformanceTypeUnknown:
return feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_UNSPECIFIED
case feature.ImprovedPerformanceTypeOrgByID:
return feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID
default:
return feature_pb.ImprovedPerformance(typ)
}
}
func improvedPerformanceListToDomain(list []feature_pb.ImprovedPerformance) []feature.ImprovedPerformanceType {
if list == nil {
return nil
}
res := make([]feature.ImprovedPerformanceType, len(list))
for i, typ := range list {
res[i] = improvedPerformanceToDomain(typ)
}
return res
}
func improvedPerformanceToDomain(typ feature_pb.ImprovedPerformance) feature.ImprovedPerformanceType {
switch typ {
case feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_UNSPECIFIED:
return feature.ImprovedPerformanceTypeUnknown
case feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID:
return feature.ImprovedPerformanceTypeOrgByID
default:
return feature.ImprovedPerformanceTypeUnknown
}
}

View File

@ -24,6 +24,7 @@ func Test_systemFeaturesToCommand(t *testing.T) {
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
}
want := &command.SystemFeatures{
LoginDefaultOrg: gu.Ptr(true),
@ -32,6 +33,7 @@ func Test_systemFeaturesToCommand(t *testing.T) {
UserSchema: gu.Ptr(true),
Actions: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
}
got := systemFeaturesToCommand(arg)
assert.Equal(t, want, got)
@ -68,6 +70,10 @@ func Test_systemFeaturesToPb(t *testing.T) {
Level: feature.LevelSystem,
Value: false,
},
ImprovedPerformance: query.FeatureSource[[]feature.ImprovedPerformanceType]{
Level: feature.LevelSystem,
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgByID},
},
}
want := &feature_pb.GetSystemFeaturesResponse{
Details: &object.Details{
@ -99,6 +105,10 @@ func Test_systemFeaturesToPb(t *testing.T) {
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
ExecutionPaths: []feature_pb.ImprovedPerformance{feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID},
Source: feature_pb.Source_SOURCE_SYSTEM,
},
}
got := systemFeaturesToPb(arg)
assert.Equal(t, want, got)
@ -112,6 +122,7 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
ImprovedPerformance: nil,
}
want := &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
@ -120,6 +131,7 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
Actions: gu.Ptr(true),
ImprovedPerformance: nil,
}
got := instanceFeaturesToCommand(arg)
assert.Equal(t, want, got)
@ -156,6 +168,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Level: feature.LevelSystem,
Value: false,
},
ImprovedPerformance: query.FeatureSource[[]feature.ImprovedPerformanceType]{
Level: feature.LevelSystem,
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgByID},
},
}
want := &feature_pb.GetInstanceFeaturesResponse{
Details: &object.Details{
@ -187,6 +203,10 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Enabled: false,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
ExecutionPaths: []feature_pb.ImprovedPerformance{feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID},
Source: feature_pb.Source_SOURCE_SYSTEM,
},
}
got := instanceFeaturesToPb(arg)
assert.Equal(t, want, got)

View File

@ -7,6 +7,7 @@ import (
"github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/feature"
"github.com/zitadel/zitadel/internal/repository/feature/feature_v2"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -18,6 +19,7 @@ type InstanceFeatures struct {
UserSchema *bool
TokenExchange *bool
Actions *bool
ImprovedPerformance []feature.ImprovedPerformanceType
}
func (m *InstanceFeatures) isEmpty() bool {
@ -26,7 +28,9 @@ func (m *InstanceFeatures) isEmpty() bool {
m.LegacyIntrospection == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
m.Actions == nil
m.Actions == nil &&
// nil check to allow unset improvements
m.ImprovedPerformance == nil
}
func (c *Commands) SetInstanceFeatures(ctx context.Context, f *InstanceFeatures) (*domain.ObjectDetails, error) {
@ -37,11 +41,11 @@ func (c *Commands) SetInstanceFeatures(ctx context.Context, f *InstanceFeatures)
if err := c.eventstore.FilterToQueryReducer(ctx, wm); err != nil {
return nil, err
}
cmds := wm.setCommands(ctx, f)
if len(cmds) == 0 {
commands := wm.setCommands(ctx, f)
if len(commands) == 0 {
return writeModelToObjectDetails(wm.WriteModel), nil
}
events, err := c.eventstore.Push(ctx, cmds...)
events, err := c.eventstore.Push(ctx, commands...)
if err != nil {
return nil, err
}

View File

@ -30,14 +30,23 @@ func (m *InstanceFeaturesWriteModel) Reduce() (err error) {
case *feature_v2.ResetEvent:
m.reduceReset()
case *feature_v1.SetEvent[feature_v1.Boolean]:
err = m.reduceBoolFeature(
feature_v1.DefaultLoginInstanceEventToV2(e),
reduceInstanceFeature(
&m.InstanceFeatures,
feature.KeyLoginDefaultOrg,
feature_v1.DefaultLoginInstanceEventToV2(e).Value,
)
case *feature_v2.SetEvent[bool]:
err = m.reduceBoolFeature(e)
}
if err != nil {
return err
_, key, err := e.FeatureInfo()
if err != nil {
return err
}
reduceInstanceFeature(&m.InstanceFeatures, key, e.Value)
case *feature_v2.SetEvent[[]feature.ImprovedPerformanceType]:
_, key, err := e.FeatureInfo()
if err != nil {
return err
}
reduceInstanceFeature(&m.InstanceFeatures, key, e.Value)
}
}
return m.WriteModel.Reduce()
@ -57,41 +66,41 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
feature_v2.InstanceImprovedPerformanceEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
func (m *InstanceFeaturesWriteModel) reduceReset() {
m.LoginDefaultOrg = nil
m.TriggerIntrospectionProjections = nil
m.LegacyIntrospection = nil
m.UserSchema = nil
m.TokenExchange = nil
m.Actions = nil
m.InstanceFeatures = InstanceFeatures{}
}
func (m *InstanceFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error {
_, key, err := event.FeatureInfo()
if err != nil {
return err
}
func reduceInstanceFeature(features *InstanceFeatures, key feature.Key, value any) {
switch key {
case feature.KeyUnspecified:
return nil
return
case feature.KeyLoginDefaultOrg:
m.LoginDefaultOrg = &event.Value
v := value.(bool)
features.LoginDefaultOrg = &v
case feature.KeyTriggerIntrospectionProjections:
m.TriggerIntrospectionProjections = &event.Value
v := value.(bool)
features.TriggerIntrospectionProjections = &v
case feature.KeyLegacyIntrospection:
m.LegacyIntrospection = &event.Value
v := value.(bool)
features.LegacyIntrospection = &v
case feature.KeyTokenExchange:
m.TokenExchange = &event.Value
v := value.(bool)
features.TokenExchange = &v
case feature.KeyUserSchema:
m.UserSchema = &event.Value
v := value.(bool)
features.UserSchema = &v
case feature.KeyActions:
m.Actions = &event.Value
v := value.(bool)
features.Actions = &v
case feature.KeyImprovedPerformance:
v := value.([]feature.ImprovedPerformanceType)
features.ImprovedPerformance = v
}
return nil
}
func (wm *InstanceFeaturesWriteModel) setCommands(ctx context.Context, f *InstanceFeatures) []eventstore.Command {
@ -103,5 +112,6 @@ func (wm *InstanceFeaturesWriteModel) setCommands(ctx context.Context, f *Instan
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.InstanceTokenExchangeEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.InstanceUserSchemaEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.Actions, f.Actions, feature_v2.InstanceActionsEventType)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.InstanceImprovedPerformanceEventType)
return cmds
}

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/feature"
"github.com/zitadel/zitadel/internal/repository/feature/feature_v2"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -15,6 +16,7 @@ type SystemFeatures struct {
TokenExchange *bool
UserSchema *bool
Actions *bool
ImprovedPerformance []feature.ImprovedPerformanceType
}
func (m *SystemFeatures) isEmpty() bool {
@ -23,7 +25,9 @@ func (m *SystemFeatures) isEmpty() bool {
m.LegacyIntrospection == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
m.Actions == nil
m.Actions == nil &&
// nil check to allow unset improvements
m.ImprovedPerformance == nil
}
func (c *Commands) SetSystemFeatures(ctx context.Context, f *SystemFeatures) (*domain.ObjectDetails, error) {

View File

@ -23,16 +23,23 @@ func NewSystemFeaturesWriteModel() *SystemFeaturesWriteModel {
return m
}
func (m *SystemFeaturesWriteModel) Reduce() (err error) {
func (m *SystemFeaturesWriteModel) Reduce() error {
for _, event := range m.Events {
switch e := event.(type) {
case *feature_v2.ResetEvent:
m.reduceReset()
case *feature_v2.SetEvent[bool]:
err = m.reduceBoolFeature(e)
}
if err != nil {
return err
_, key, err := e.FeatureInfo()
if err != nil {
return err
}
reduceSystemFeature(&m.SystemFeatures, key, e.Value)
case *feature_v2.SetEvent[[]feature.ImprovedPerformanceType]:
_, key, err := e.FeatureInfo()
if err != nil {
return err
}
reduceSystemFeature(&m.SystemFeatures, key, e.Value)
}
}
return m.WriteModel.Reduce()
@ -52,41 +59,40 @@ func (m *SystemFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
feature_v2.SystemImprovedPerformanceEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
func (m *SystemFeaturesWriteModel) reduceReset() {
m.LoginDefaultOrg = nil
m.TriggerIntrospectionProjections = nil
m.LegacyIntrospection = nil
m.TokenExchange = nil
m.UserSchema = nil
m.Actions = nil
m.SystemFeatures = SystemFeatures{}
}
func (m *SystemFeaturesWriteModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error {
_, key, err := event.FeatureInfo()
if err != nil {
return err
}
func reduceSystemFeature(features *SystemFeatures, key feature.Key, value any) {
switch key {
case feature.KeyUnspecified:
return nil
return
case feature.KeyLoginDefaultOrg:
m.LoginDefaultOrg = &event.Value
v := value.(bool)
features.LoginDefaultOrg = &v
case feature.KeyTriggerIntrospectionProjections:
m.TriggerIntrospectionProjections = &event.Value
v := value.(bool)
features.TriggerIntrospectionProjections = &v
case feature.KeyLegacyIntrospection:
m.LegacyIntrospection = &event.Value
v := value.(bool)
features.LegacyIntrospection = &v
case feature.KeyUserSchema:
m.UserSchema = &event.Value
v := value.(bool)
features.UserSchema = &v
case feature.KeyTokenExchange:
m.TokenExchange = &event.Value
v := value.(bool)
features.TokenExchange = &v
case feature.KeyActions:
m.Actions = &event.Value
v := value.(bool)
features.Actions = &v
case feature.KeyImprovedPerformance:
features.ImprovedPerformance = value.([]feature.ImprovedPerformanceType)
}
return nil
}
func (wm *SystemFeaturesWriteModel) setCommands(ctx context.Context, f *SystemFeatures) []eventstore.Command {
@ -98,6 +104,7 @@ func (wm *SystemFeaturesWriteModel) setCommands(ctx context.Context, f *SystemFe
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.SystemUserSchemaEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.SystemTokenExchangeEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.Actions, f.Actions, feature_v2.SystemActionsEventType)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.SystemImprovedPerformanceEventType)
return cmds
}
@ -107,3 +114,15 @@ func appendFeatureUpdate[T comparable](ctx context.Context, cmds []eventstore.Co
}
return cmds
}
func appendFeatureSliceUpdate[T comparable](ctx context.Context, cmds []eventstore.Command, aggregate *feature_v2.Aggregate, oldValues, newValues []T, eventType eventstore.EventType) []eventstore.Command {
if len(newValues) != len(oldValues) {
return append(cmds, feature_v2.NewSetEvent[[]T](ctx, aggregate, eventType, newValues))
}
for i, oldValue := range oldValues {
if oldValue != newValues[i] {
return append(cmds, feature_v2.NewSetEvent[[]T](ctx, aggregate, eventType, newValues))
}
}
return cmds
}

View File

@ -11,6 +11,7 @@ const (
KeyUserSchema
KeyTokenExchange
KeyActions
KeyImprovedPerformance
)
//go:generate enumer -type Level -transform snake -trimprefix Level
@ -27,10 +28,27 @@ const (
)
type Features struct {
LoginDefaultOrg bool `json:"login_default_org,omitempty"`
TriggerIntrospectionProjections bool `json:"trigger_introspection_projections,omitempty"`
LegacyIntrospection bool `json:"legacy_introspection,omitempty"`
UserSchema bool `json:"user_schema,omitempty"`
TokenExchange bool `json:"token_exchange,omitempty"`
Actions bool `json:"actions,omitempty"`
LoginDefaultOrg bool `json:"login_default_org,omitempty"`
TriggerIntrospectionProjections bool `json:"trigger_introspection_projections,omitempty"`
LegacyIntrospection bool `json:"legacy_introspection,omitempty"`
UserSchema bool `json:"user_schema,omitempty"`
TokenExchange bool `json:"token_exchange,omitempty"`
Actions bool `json:"actions,omitempty"`
ImprovedPerformance []ImprovedPerformanceType `json:"improved_performance,omitempty"`
}
type ImprovedPerformanceType int32
const (
ImprovedPerformanceTypeUnknown = iota
ImprovedPerformanceTypeOrgByID
)
func (f Features) ShouldUseImprovedPerformance(typ ImprovedPerformanceType) bool {
for _, improvedType := range f.ImprovedPerformance {
if improvedType == typ {
return true
}
}
return false
}

View File

@ -7,11 +7,11 @@ import (
"strings"
)
const _KeyName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactions"
const _KeyName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactionsimproved_performance"
var _KeyIndex = [...]uint8{0, 11, 28, 61, 81, 92, 106, 113}
var _KeyIndex = [...]uint8{0, 11, 28, 61, 81, 92, 106, 113, 133}
const _KeyLowerName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactions"
const _KeyLowerName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactionsimproved_performance"
func (i Key) String() string {
if i < 0 || i >= Key(len(_KeyIndex)-1) {
@ -31,9 +31,10 @@ func _KeyNoOp() {
_ = x[KeyUserSchema-(4)]
_ = x[KeyTokenExchange-(5)]
_ = x[KeyActions-(6)]
_ = x[KeyImprovedPerformance-(7)]
}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActions}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActions, KeyImprovedPerformance}
var _KeyNameToValueMap = map[string]Key{
_KeyName[0:11]: KeyUnspecified,
@ -50,6 +51,8 @@ var _KeyNameToValueMap = map[string]Key{
_KeyLowerName[92:106]: KeyTokenExchange,
_KeyName[106:113]: KeyActions,
_KeyLowerName[106:113]: KeyActions,
_KeyName[113:133]: KeyImprovedPerformance,
_KeyLowerName[113:133]: KeyImprovedPerformance,
}
var _KeyNames = []string{
@ -60,6 +63,7 @@ var _KeyNames = []string{
_KeyName[81:92],
_KeyName[92:106],
_KeyName[106:113],
_KeyName[113:133],
}
// KeyString retrieves an enum value from the enum constants string name.

View File

@ -4,6 +4,7 @@ import (
"context"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/feature"
)
type InstanceFeatures struct {
@ -14,6 +15,7 @@ type InstanceFeatures struct {
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]
}
func (q *Queries) GetInstanceFeatures(ctx context.Context, cascade bool) (_ *InstanceFeatures, err error) {

View File

@ -36,11 +36,14 @@ func (m *InstanceFeaturesReadModel) Reduce() (err error) {
case *feature_v2.ResetEvent:
m.reduceReset()
case *feature_v1.SetEvent[feature_v1.Boolean]:
err = m.reduceBoolFeature(
err = reduceInstanceFeatureSet(
m.instance,
feature_v1.DefaultLoginInstanceEventToV2(e),
)
case *feature_v2.SetEvent[bool]:
err = m.reduceBoolFeature(e)
err = reduceInstanceFeatureSet(m.instance, e)
case *feature_v2.SetEvent[[]feature.ImprovedPerformanceType]:
err = reduceInstanceFeatureSet(m.instance, e)
}
if err != nil {
return err
@ -63,6 +66,7 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceActionsEventType,
feature_v2.InstanceImprovedPerformanceEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
@ -71,12 +75,8 @@ func (m *InstanceFeaturesReadModel) reduceReset() {
if m.populateFromSystem() {
return
}
m.instance.LoginDefaultOrg = FeatureSource[bool]{}
m.instance.TriggerIntrospectionProjections = FeatureSource[bool]{}
m.instance.LegacyIntrospection = FeatureSource[bool]{}
m.instance.UserSchema = FeatureSource[bool]{}
m.instance.TokenExchange = FeatureSource[bool]{}
m.instance.Actions = FeatureSource[bool]{}
m.instance = nil
m.instance = new(InstanceFeatures)
}
func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
@ -89,35 +89,32 @@ func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
m.instance.UserSchema = m.system.UserSchema
m.instance.TokenExchange = m.system.TokenExchange
m.instance.Actions = m.system.Actions
m.instance.ImprovedPerformance = m.system.ImprovedPerformance
return true
}
func (m *InstanceFeaturesReadModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error {
func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_v2.SetEvent[T]) error {
level, key, err := event.FeatureInfo()
if err != nil {
return err
}
var dst *FeatureSource[bool]
switch key {
case feature.KeyUnspecified:
return nil
case feature.KeyLoginDefaultOrg:
dst = &m.instance.LoginDefaultOrg
features.LoginDefaultOrg.set(level, event.Value)
case feature.KeyTriggerIntrospectionProjections:
dst = &m.instance.TriggerIntrospectionProjections
features.TriggerIntrospectionProjections.set(level, event.Value)
case feature.KeyLegacyIntrospection:
dst = &m.instance.LegacyIntrospection
features.LegacyIntrospection.set(level, event.Value)
case feature.KeyUserSchema:
dst = &m.instance.UserSchema
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:
dst = &m.instance.TokenExchange
features.TokenExchange.set(level, event.Value)
case feature.KeyActions:
dst = &m.instance.Actions
}
*dst = FeatureSource[bool]{
Level: level,
Value: event.Value,
features.Actions.set(level, event.Value)
case feature.KeyImprovedPerformance:
features.ImprovedPerformance.set(level, event.Value)
}
return nil
}

View File

@ -13,8 +13,11 @@ import (
"github.com/zitadel/zitadel/internal/api/call"
domain_pkg "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/feature"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
"github.com/zitadel/zitadel/internal/v2/eventstore"
"github.com/zitadel/zitadel/internal/v2/readmodel"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -92,7 +95,44 @@ func (q *OrgSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
return query
}
func (q *Queries) OrgByID(ctx context.Context, shouldTriggerBulk bool, id string) (org *Org, err error) {
func (q *Queries) OrgByID(ctx context.Context, shouldTriggerBulk bool, id string) (_ *Org, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if !authz.GetInstance(ctx).Features().ShouldUseImprovedPerformance(feature.ImprovedPerformanceTypeOrgByID) {
return q.oldOrgByID(ctx, shouldTriggerBulk, id)
}
foundOrg := readmodel.NewOrg(id)
eventCount, err := q.eventStoreV4.Query(
ctx,
eventstore.NewQuery(
authz.GetInstance(ctx).InstanceID(),
foundOrg,
eventstore.AppendFilters(foundOrg.Filter()...),
),
)
if err != nil {
return nil, zerrors.ThrowInternal(err, "QUERY-AWx52", "Errors.Query.SQLStatement")
}
if eventCount == 0 {
return nil, zerrors.ThrowNotFound(nil, "QUERY-leq5Q", "Errors.Org.NotFound")
}
return &Org{
ID: foundOrg.ID,
CreationDate: foundOrg.CreationDate,
ChangeDate: foundOrg.ChangeDate,
ResourceOwner: foundOrg.Owner,
State: domain_pkg.OrgState(foundOrg.State.State),
Sequence: uint64(foundOrg.Sequence),
Name: foundOrg.Name,
Domain: foundOrg.PrimaryDomain.Domain,
}, nil
}
func (q *Queries) oldOrgByID(ctx context.Context, shouldTriggerBulk bool, id string) (org *Org, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()

View File

@ -6,6 +6,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore"
old_handler "github.com/zitadel/zitadel/internal/eventstore/handler"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/feature"
feature_v1 "github.com/zitadel/zitadel/internal/repository/feature"
"github.com/zitadel/zitadel/internal/repository/feature/feature_v2"
"github.com/zitadel/zitadel/internal/repository/instance"
@ -83,6 +84,10 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.InstanceActionsEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceImprovedPerformanceEventType,
Reduce: reduceInstanceSetFeature[[]feature.ImprovedPerformanceType],
},
{
Event: instance.InstanceRemovedEventType,
Reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol),

View File

@ -6,6 +6,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore"
old_handler "github.com/zitadel/zitadel/internal/eventstore/handler"
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/feature"
"github.com/zitadel/zitadel/internal/repository/feature/feature_v2"
"github.com/zitadel/zitadel/internal/zerrors"
)
@ -75,6 +76,10 @@ func (*systemFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.SystemActionsEventType,
Reduce: reduceSystemSetFeature[bool],
},
{
Event: feature_v2.SystemImprovedPerformanceEventType,
Reduce: reduceSystemSetFeature[[]feature.ImprovedPerformanceType],
},
},
}}
}

View File

@ -19,11 +19,14 @@ import (
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
"github.com/zitadel/zitadel/internal/query/projection"
"github.com/zitadel/zitadel/internal/telemetry/tracing"
es_v4 "github.com/zitadel/zitadel/internal/v2/eventstore"
"github.com/zitadel/zitadel/internal/v2/eventstore/postgres"
)
type Queries struct {
eventstore *eventstore.Eventstore
client *database.DB
eventstore *eventstore.Eventstore
eventStoreV4 es_v4.Querier
client *database.DB
keyEncryptionAlgorithm crypto.EncryptionAlgorithm
idpConfigEncryption crypto.EncryptionAlgorithm
@ -56,6 +59,7 @@ func StartQueries(
) (repo *Queries, err error) {
repo = &Queries{
eventstore: es,
eventStoreV4: postgres.New(querySqlClient),
client: querySqlClient,
DefaultLanguage: language.Und,
LoginTranslationFileContents: make(map[string][]byte),

View File

@ -12,6 +12,11 @@ type FeatureSource[T any] struct {
Value T
}
func (f *FeatureSource[T]) set(level feature.Level, value any) {
f.Level = level
f.Value = value.(T)
}
type SystemFeatures struct {
Details *domain.ObjectDetails
@ -21,6 +26,7 @@ type SystemFeatures struct {
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
Actions FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]
}
func (q *Queries) GetSystemFeatures(ctx context.Context) (_ *SystemFeatures, err error) {

View File

@ -28,7 +28,12 @@ func (m *SystemFeaturesReadModel) Reduce() error {
case *feature_v2.ResetEvent:
m.reduceReset()
case *feature_v2.SetEvent[bool]:
err := m.reduceBoolFeature(e)
err := reduceSystemFeatureSet(m.system, e)
if err != nil {
return err
}
case *feature_v2.SetEvent[[]feature.ImprovedPerformanceType]:
err := reduceSystemFeatureSet(m.system, e)
if err != nil {
return err
}
@ -51,41 +56,38 @@ func (m *SystemFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemActionsEventType,
feature_v2.SystemImprovedPerformanceEventType,
).
Builder().ResourceOwner(m.ResourceOwner)
}
func (m *SystemFeaturesReadModel) reduceReset() {
m.system = nil
m.system = new(SystemFeatures)
}
func (m *SystemFeaturesReadModel) reduceBoolFeature(event *feature_v2.SetEvent[bool]) error {
func reduceSystemFeatureSet[T any](features *SystemFeatures, event *feature_v2.SetEvent[T]) error {
level, key, err := event.FeatureInfo()
if err != nil {
return err
}
var dst *FeatureSource[bool]
switch key {
case feature.KeyUnspecified:
return nil
case feature.KeyLoginDefaultOrg:
dst = &m.system.LoginDefaultOrg
features.LoginDefaultOrg.set(level, event.Value)
case feature.KeyTriggerIntrospectionProjections:
dst = &m.system.TriggerIntrospectionProjections
features.TriggerIntrospectionProjections.set(level, event.Value)
case feature.KeyLegacyIntrospection:
dst = &m.system.LegacyIntrospection
features.LegacyIntrospection.set(level, event.Value)
case feature.KeyUserSchema:
dst = &m.system.UserSchema
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:
dst = &m.system.TokenExchange
features.TokenExchange.set(level, event.Value)
case feature.KeyActions:
dst = &m.system.Actions
}
*dst = FeatureSource[bool]{
Level: level,
Value: event.Value,
features.Actions.set(level, event.Value)
case feature.KeyImprovedPerformance:
features.ImprovedPerformance.set(level, event.Value)
}
return nil
}

View File

@ -2,6 +2,7 @@ package feature_v2
import (
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/feature"
)
func init() {
@ -12,6 +13,8 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, SystemUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemActionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceResetEventType, eventstore.GenericEventMapper[ResetEvent])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTriggerIntrospectionProjectionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
@ -19,4 +22,5 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, InstanceUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceActionsEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])
}

View File

@ -18,6 +18,7 @@ var (
SystemUserSchemaEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyUserSchema)
SystemTokenExchangeEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyTokenExchange)
SystemActionsEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyActions)
SystemImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyImprovedPerformance)
InstanceResetEventType = resetEventTypeFromFeature(feature.LevelInstance)
InstanceLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLoginDefaultOrg)
@ -26,6 +27,7 @@ var (
InstanceUserSchemaEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyUserSchema)
InstanceTokenExchangeEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTokenExchange)
InstanceActionsEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyActions)
InstanceImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyImprovedPerformance)
)
const (

View File

@ -0,0 +1,57 @@
package projection
import (
"github.com/zitadel/zitadel/internal/v2/eventstore"
"github.com/zitadel/zitadel/internal/v2/org"
)
type OrgPrimaryDomain struct {
projection
id string
Domain string
}
func NewOrgPrimaryDomain(id string) *OrgPrimaryDomain {
return &OrgPrimaryDomain{
id: id,
}
}
func (p *OrgPrimaryDomain) Filter() []*eventstore.Filter {
return []*eventstore.Filter{
eventstore.NewFilter(
eventstore.FilterPagination(
eventstore.GlobalPositionGreater(&p.position),
),
eventstore.AppendAggregateFilter(
org.AggregateType,
eventstore.AggregateIDs(p.id),
eventstore.AppendEvent(
eventstore.SetEventTypes(org.DomainPrimarySetType),
),
),
),
}
}
func (p *OrgPrimaryDomain) Reduce(events ...*eventstore.StorageEvent) error {
for _, event := range events {
if !p.shouldReduce(event) {
continue
}
if event.Type != org.DomainPrimarySetType {
continue
}
e, err := org.DomainPrimarySetEventFromStorage(event)
if err != nil {
return err
}
p.Domain = e.Payload.Name
p.projection.reduce(event)
}
return nil
}

View File

@ -0,0 +1,67 @@
package projection
import (
"github.com/zitadel/zitadel/internal/v2/eventstore"
"github.com/zitadel/zitadel/internal/v2/org"
)
type OrgState struct {
projection
id string
org.State
}
func NewStateProjection(id string) *OrgState {
// TODO: check buffer for id and return from buffer if exists
return &OrgState{
id: id,
}
}
func (p *OrgState) Filter() []*eventstore.Filter {
return []*eventstore.Filter{
eventstore.NewFilter(
eventstore.FilterPagination(
eventstore.Descending(),
eventstore.GlobalPositionGreater(&p.position),
),
eventstore.AppendAggregateFilter(
org.AggregateType,
eventstore.AggregateIDs(p.id),
eventstore.AppendEvent(
eventstore.SetEventTypes(
org.AddedType,
org.DeactivatedType,
org.ReactivatedType,
org.RemovedType,
),
),
),
),
}
}
func (p *OrgState) Reduce(events ...*eventstore.StorageEvent) error {
for _, event := range events {
if !p.shouldReduce(event) {
continue
}
switch event.Type {
case org.AddedType:
p.State = org.ActiveState
case org.DeactivatedType:
p.State = org.InactiveState
case org.ReactivatedType:
p.State = org.ActiveState
case org.RemovedType:
p.State = org.RemovedState
default:
continue
}
p.position = event.Position
}
return nil
}

View File

@ -0,0 +1,20 @@
package projection
import "github.com/zitadel/zitadel/internal/v2/eventstore"
type projection struct {
instance string
position eventstore.GlobalPosition
}
func (p *projection) reduce(event *eventstore.StorageEvent) {
if p.instance == "" {
p.instance = event.Aggregate.Instance
}
p.position = event.Position
}
func (p *projection) shouldReduce(event *eventstore.StorageEvent) bool {
shouldReduce := p.instance == "" || p.instance == event.Aggregate.Instance
return shouldReduce && p.position.IsLess(event.Position)
}

View File

@ -0,0 +1,68 @@
package readmodel
import (
"time"
"github.com/zitadel/zitadel/internal/v2/eventstore"
"github.com/zitadel/zitadel/internal/v2/org"
"github.com/zitadel/zitadel/internal/v2/projection"
)
type Org struct {
ID string
Name string
PrimaryDomain *projection.OrgPrimaryDomain
State *projection.OrgState
Sequence uint32
CreationDate time.Time
ChangeDate time.Time
Owner string
}
func NewOrg(id string) *Org {
return &Org{
ID: id,
State: projection.NewStateProjection(id),
PrimaryDomain: projection.NewOrgPrimaryDomain(id),
}
}
func (rm *Org) Filter() []*eventstore.Filter {
return []*eventstore.Filter{
// we don't need the filters of the projections as we filter all events of the read model
eventstore.NewFilter(
eventstore.AppendAggregateFilter(
org.AggregateType,
eventstore.SetAggregateID(rm.ID),
),
),
}
}
func (rm *Org) Reduce(events ...*eventstore.StorageEvent) error {
for _, event := range events {
switch event.Type {
case org.AddedType:
added, err := org.AddedEventFromStorage(event)
if err != nil {
return err
}
rm.Name = added.Payload.Name
rm.Owner = event.Aggregate.Owner
rm.CreationDate = event.CreatedAt
case org.ChangedType:
changed, err := org.ChangedEventFromStorage(event)
if err != nil {
return err
}
rm.Name = changed.Payload.Name
}
rm.Sequence = event.Sequence
rm.ChangeDate = event.CreatedAt
}
if err := rm.State.Reduce(events...); err != nil {
return err
}
return rm.PrimaryDomain.Reduce(events...)
}

View File

@ -0,0 +1,15 @@
package readmodel
import (
"database/sql"
"github.com/zitadel/zitadel/internal/v2/eventstore"
)
type QueryOpt func(opts []eventstore.QueryOpt) []eventstore.QueryOpt
func WithTx(tx *sql.Tx) QueryOpt {
return func(opts []eventstore.QueryOpt) []eventstore.QueryOpt {
return append(opts, eventstore.SetQueryTx(tx))
}
}

View File

@ -33,3 +33,25 @@ message FeatureFlag {
}
];
}
message ImprovedPerformanceFeatureFlag {
repeated ImprovedPerformance execution_paths = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";
description: "Which of the performance improvements is enabled";
}
];
Source source = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "The source where the setting of the feature was defined. The source may be the resource itself or a resource owner through inheritance.";
}
];
}
enum ImprovedPerformance {
IMPROVED_PERFORMANCE_UNSPECIFIED = 0;
// Uses the eventstore to query the org by id
// instead of the sql table.
IMPROVED_PERFORMANCE_ORG_BY_ID = 1;
}

View File

@ -49,6 +49,15 @@ message SetInstanceFeaturesRequest{
description: "Actions allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
repeated ImprovedPerformance improved_performance = 7 [
(validate.rules).repeated.unique = true,
(validate.rules).repeated.items.enum = {defined_only: true, not_in: [0]},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";
description: "Improves performance of specified execution paths.";
}
];
}
message SetInstanceFeaturesResponse {
@ -113,4 +122,11 @@ message GetInstanceFeaturesResponse {
description: "Actions v2 allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";
description: "Improves performance of specified execution paths.";
}
];
}

View File

@ -46,13 +46,21 @@ message SetSystemFeaturesRequest{
}
];
optional bool actions = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Actions allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
repeated ImprovedPerformance improved_performance = 7 [
(validate.rules).repeated.unique = true,
(validate.rules).repeated.items.enum = {defined_only: true, not_in: [0]},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";
description: "Improves performance of specified execution paths.";
}
];
}
message SetSystemFeaturesResponse {
@ -110,4 +118,11 @@ message GetSystemFeaturesResponse {
description: "Actions v2 allow to manage data executions and targets. If the flag is enabled, you'll be able to use the new API and its features. Note that it is still in an early stage.";
}
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "[1]";
description: "Improves performance of specified execution paths.";
}
];
}