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
27 changed files with 587 additions and 104 deletions

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))
}
}