mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:07:31 +00:00
feat: handle instanceID in projections (#3442)
* feat: handle instanceID in projections * rename functions * fix key lock * fix import
This commit is contained in:
@@ -17,7 +17,7 @@ CREATE TABLE eventstore.events (
|
|||||||
, PRIMARY KEY (event_sequence DESC, instance_id) USING HASH WITH BUCKET_COUNT = 10
|
, PRIMARY KEY (event_sequence DESC, instance_id) USING HASH WITH BUCKET_COUNT = 10
|
||||||
, INDEX agg_type_agg_id (aggregate_type, aggregate_id, instance_id)
|
, INDEX agg_type_agg_id (aggregate_type, aggregate_id, instance_id)
|
||||||
, INDEX agg_type (aggregate_type, instance_id)
|
, INDEX agg_type (aggregate_type, instance_id)
|
||||||
, INDEX agg_type_seq (aggregate_type, event_sequence DESC, instance_id)
|
, INDEX agg_type_seq (aggregate_type, event_sequence DESC, instance_id)
|
||||||
STORING (id, event_type, aggregate_id, aggregate_version, previous_aggregate_sequence, creation_date, event_data, editor_user, editor_service, resource_owner, previous_aggregate_type_sequence)
|
STORING (id, event_type, aggregate_id, aggregate_version, previous_aggregate_sequence, creation_date, event_data, editor_user, editor_service, resource_owner, previous_aggregate_type_sequence)
|
||||||
, INDEX max_sequence (aggregate_type, aggregate_id, event_sequence DESC, instance_id)
|
, INDEX max_sequence (aggregate_type, aggregate_id, event_sequence DESC, instance_id)
|
||||||
, CONSTRAINT previous_sequence_unique UNIQUE (previous_aggregate_sequence DESC, instance_id)
|
, CONSTRAINT previous_sequence_unique UNIQUE (previous_aggregate_sequence DESC, instance_id)
|
||||||
|
@@ -4,8 +4,9 @@ CREATE TABLE adminapi.locks (
|
|||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
view_name TEXT,
|
view_name TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adminapi.current_sequences (
|
CREATE TABLE adminapi.current_sequences (
|
||||||
@@ -13,8 +14,9 @@ CREATE TABLE adminapi.current_sequences (
|
|||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
event_timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
last_successful_spooler_run TIMESTAMPTZ,
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adminapi.failed_events (
|
CREATE TABLE adminapi.failed_events (
|
||||||
@@ -22,8 +24,9 @@ CREATE TABLE adminapi.failed_events (
|
|||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
err_msg TEXT,
|
err_msg TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE adminapi.styling (
|
CREATE TABLE adminapi.styling (
|
||||||
@@ -50,5 +53,5 @@ CREATE TABLE adminapi.styling (
|
|||||||
hide_login_name_suffix BOOL NULL,
|
hide_login_name_suffix BOOL NULL,
|
||||||
instance_id STRING NOT NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (aggregate_id, label_policy_state)
|
PRIMARY KEY (aggregate_id, label_policy_state, instance_id)
|
||||||
);
|
);
|
||||||
|
@@ -4,8 +4,9 @@ CREATE TABLE auth.locks (
|
|||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
view_name TEXT,
|
view_name TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.current_sequences (
|
CREATE TABLE auth.current_sequences (
|
||||||
@@ -13,8 +14,9 @@ CREATE TABLE auth.current_sequences (
|
|||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
event_timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
last_successful_spooler_run TIMESTAMPTZ,
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.failed_events (
|
CREATE TABLE auth.failed_events (
|
||||||
@@ -22,8 +24,9 @@ CREATE TABLE auth.failed_events (
|
|||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
err_msg TEXT,
|
err_msg TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.users (
|
CREATE TABLE auth.users (
|
||||||
@@ -68,9 +71,9 @@ CREATE TABLE auth.users (
|
|||||||
avatar_key STRING NULL,
|
avatar_key STRING NULL,
|
||||||
passwordless_init_required BOOL NULL,
|
passwordless_init_required BOOL NULL,
|
||||||
password_init_required BOOL NULL,
|
password_init_required BOOL NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.user_sessions (
|
CREATE TABLE auth.user_sessions (
|
||||||
@@ -93,9 +96,9 @@ CREATE TABLE auth.user_sessions (
|
|||||||
selected_idp_config_id STRING NULL,
|
selected_idp_config_id STRING NULL,
|
||||||
passwordless_verification TIMESTAMPTZ NULL,
|
passwordless_verification TIMESTAMPTZ NULL,
|
||||||
avatar_key STRING NULL,
|
avatar_key STRING NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (user_agent_id, user_id)
|
PRIMARY KEY (user_agent_id, user_id, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.user_external_idps (
|
CREATE TABLE auth.user_external_idps (
|
||||||
@@ -108,9 +111,9 @@ CREATE TABLE auth.user_external_idps (
|
|||||||
change_date TIMESTAMPTZ NULL,
|
change_date TIMESTAMPTZ NULL,
|
||||||
sequence INT8 NULL,
|
sequence INT8 NULL,
|
||||||
resource_owner STRING NULL,
|
resource_owner STRING NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (external_user_id, idp_config_id)
|
PRIMARY KEY (external_user_id, idp_config_id, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.tokens (
|
CREATE TABLE auth.tokens (
|
||||||
@@ -128,9 +131,9 @@ CREATE TABLE auth.tokens (
|
|||||||
preferred_language STRING NULL,
|
preferred_language STRING NULL,
|
||||||
refresh_token_id STRING NULL,
|
refresh_token_id STRING NULL,
|
||||||
is_pat BOOL NOT NULL DEFAULT false,
|
is_pat BOOL NOT NULL DEFAULT false,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id, instance_id),
|
||||||
INDEX user_user_agent_idx (user_id, user_agent_id)
|
INDEX user_user_agent_idx (user_id, user_agent_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -150,19 +153,19 @@ CREATE TABLE auth.refresh_tokens (
|
|||||||
scopes STRING[] NULL,
|
scopes STRING[] NULL,
|
||||||
audience STRING[] NULL,
|
audience STRING[] NULL,
|
||||||
amr STRING[] NULL,
|
amr STRING[] NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id, instance_id),
|
||||||
UNIQUE INDEX unique_client_user_index (client_id ASC, user_agent_id ASC, user_id ASC)
|
UNIQUE INDEX unique_client_user_index (client_id ASC, user_agent_id ASC, user_id ASC, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.org_project_mapping (
|
CREATE TABLE auth.org_project_mapping (
|
||||||
org_id STRING NOT NULL,
|
org_id STRING NOT NULL,
|
||||||
project_id STRING NOT NULL,
|
project_id STRING NOT NULL,
|
||||||
project_grant_id STRING NULL,
|
project_grant_id STRING NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (org_id, project_id)
|
PRIMARY KEY (org_id, project_id, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.idp_providers (
|
CREATE TABLE auth.idp_providers (
|
||||||
@@ -176,9 +179,9 @@ CREATE TABLE auth.idp_providers (
|
|||||||
idp_provider_type INT2 NULL,
|
idp_provider_type INT2 NULL,
|
||||||
idp_state INT2 NULL,
|
idp_state INT2 NULL,
|
||||||
styling_type INT2 NULL,
|
styling_type INT2 NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (aggregate_id, idp_config_id)
|
PRIMARY KEY (aggregate_id, idp_config_id, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.idp_configs (
|
CREATE TABLE auth.idp_configs (
|
||||||
@@ -204,9 +207,9 @@ CREATE TABLE auth.idp_configs (
|
|||||||
jwt_endpoint STRING NULL,
|
jwt_endpoint STRING NULL,
|
||||||
jwt_keys_endpoint STRING NULL,
|
jwt_keys_endpoint STRING NULL,
|
||||||
jwt_header_name STRING NULL,
|
jwt_header_name STRING NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (idp_config_id)
|
PRIMARY KEY (idp_config_id, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE auth.auth_requests (
|
CREATE TABLE auth.auth_requests (
|
||||||
@@ -216,8 +219,8 @@ CREATE TABLE auth.auth_requests (
|
|||||||
request_type INT2 NULL,
|
request_type INT2 NULL,
|
||||||
creation_date TIMESTAMPTZ NULL,
|
creation_date TIMESTAMPTZ NULL,
|
||||||
change_date TIMESTAMPTZ NULL,
|
change_date TIMESTAMPTZ NULL,
|
||||||
instance_id STRING NULL,
|
instance_id STRING NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id, instance_id),
|
||||||
INDEX auth_code_idx (code)
|
INDEX auth_code_idx (code)
|
||||||
);
|
);
|
||||||
|
@@ -4,8 +4,9 @@ CREATE TABLE authz.locks (
|
|||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
view_name TEXT,
|
view_name TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE authz.current_sequences (
|
CREATE TABLE authz.current_sequences (
|
||||||
@@ -13,8 +14,9 @@ CREATE TABLE authz.current_sequences (
|
|||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
event_timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
last_successful_spooler_run TIMESTAMPTZ,
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE authz.failed_events (
|
CREATE TABLE authz.failed_events (
|
||||||
@@ -22,8 +24,9 @@ CREATE TABLE authz.failed_events (
|
|||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
err_msg TEXT,
|
err_msg TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE authz.user_memberships (
|
CREATE TABLE authz.user_memberships (
|
||||||
|
@@ -4,8 +4,9 @@ CREATE TABLE notification.locks (
|
|||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
view_name TEXT,
|
view_name TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE notification.current_sequences (
|
CREATE TABLE notification.current_sequences (
|
||||||
@@ -13,8 +14,9 @@ CREATE TABLE notification.current_sequences (
|
|||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
event_timestamp TIMESTAMPTZ,
|
event_timestamp TIMESTAMPTZ,
|
||||||
last_successful_spooler_run TIMESTAMPTZ,
|
last_successful_spooler_run TIMESTAMPTZ,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name)
|
PRIMARY KEY (view_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE notification.failed_events (
|
CREATE TABLE notification.failed_events (
|
||||||
@@ -22,8 +24,9 @@ CREATE TABLE notification.failed_events (
|
|||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
err_msg TEXT,
|
err_msg TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (view_name, failed_sequence)
|
PRIMARY KEY (view_name, failed_sequence, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE notification.notify_users (
|
CREATE TABLE notification.notify_users (
|
||||||
|
@@ -2,17 +2,19 @@ CREATE TABLE projections.locks (
|
|||||||
locker_id TEXT,
|
locker_id TEXT,
|
||||||
locked_until TIMESTAMPTZ(3),
|
locked_until TIMESTAMPTZ(3),
|
||||||
projection_name TEXT,
|
projection_name TEXT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name)
|
PRIMARY KEY (projection_name, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE projections.current_sequences (
|
CREATE TABLE projections.current_sequences (
|
||||||
projection_name TEXT,
|
projection_name TEXT,
|
||||||
aggregate_type TEXT,
|
aggregate_type TEXT,
|
||||||
current_sequence BIGINT,
|
current_sequence BIGINT,
|
||||||
|
instance_id TEXT NOT NULL,
|
||||||
timestamp TIMESTAMPTZ,
|
timestamp TIMESTAMPTZ,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, aggregate_type)
|
PRIMARY KEY (projection_name, aggregate_type, instance_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE projections.failed_events (
|
CREATE TABLE projections.failed_events (
|
||||||
@@ -20,7 +22,7 @@ CREATE TABLE projections.failed_events (
|
|||||||
failed_sequence BIGINT,
|
failed_sequence BIGINT,
|
||||||
failure_count SMALLINT,
|
failure_count SMALLINT,
|
||||||
error TEXT,
|
error TEXT,
|
||||||
instance_id TEXT,
|
instance_id TEXT NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (projection_name, failed_sequence, instance_id)
|
PRIMARY KEY (projection_name, failed_sequence, instance_id)
|
||||||
);
|
);
|
||||||
|
@@ -60,7 +60,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
|||||||
steps.S3DefaultInstance.db = dbClient
|
steps.S3DefaultInstance.db = dbClient
|
||||||
steps.S3DefaultInstance.defaults = config.SystemDefaults
|
steps.S3DefaultInstance.defaults = config.SystemDefaults
|
||||||
steps.S3DefaultInstance.masterKey = masterKey
|
steps.S3DefaultInstance.masterKey = masterKey
|
||||||
steps.S3DefaultInstance.domain = config.SystemDefaults.Domain
|
steps.S3DefaultInstance.domain = config.ExternalDomain
|
||||||
steps.S3DefaultInstance.zitadelRoles = config.InternalAuthZ.RolePermissionMappings
|
steps.S3DefaultInstance.zitadelRoles = config.InternalAuthZ.RolePermissionMappings
|
||||||
steps.S3DefaultInstance.userEncryptionKey = config.EncryptionKeys.User
|
steps.S3DefaultInstance.userEncryptionKey = config.EncryptionKeys.User
|
||||||
steps.S3DefaultInstance.InstanceSetup.Zitadel.IsDevMode = !config.ExternalSecure
|
steps.S3DefaultInstance.InstanceSetup.Zitadel.IsDevMode = !config.ExternalSecure
|
||||||
|
@@ -2,6 +2,7 @@ package repository
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/view/model"
|
"github.com/caos/zitadel/internal/view/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -9,6 +10,5 @@ type AdministratorRepository interface {
|
|||||||
GetFailedEvents(context.Context) ([]*model.FailedEvent, error)
|
GetFailedEvents(context.Context) ([]*model.FailedEvent, error)
|
||||||
RemoveFailedEvent(context.Context, *model.FailedEvent) error
|
RemoveFailedEvent(context.Context, *model.FailedEvent) error
|
||||||
GetViews() ([]*model.View, error)
|
GetViews() ([]*model.View, error)
|
||||||
GetSpoolerDiv(db, viewName string) int64
|
|
||||||
ClearView(ctx context.Context, db, viewName string) error
|
ClearView(ctx context.Context, db, viewName string) error
|
||||||
}
|
}
|
||||||
|
@@ -2,14 +2,13 @@ package eventstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
|
||||||
view_model "github.com/caos/zitadel/internal/view/model"
|
view_model "github.com/caos/zitadel/internal/view/model"
|
||||||
"github.com/caos/zitadel/internal/view/repository"
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
var dbList = []string{"management", "auth", "authz", "adminapi", "notification"}
|
var dbList = []string{"auth", "authz", "adminapi", "notification"}
|
||||||
|
|
||||||
type AdministratorRepo struct {
|
type AdministratorRepo struct {
|
||||||
View *view.View
|
View *view.View
|
||||||
@@ -47,16 +46,6 @@ func (repo *AdministratorRepo) GetViews() ([]*view_model.View, error) {
|
|||||||
return views, nil
|
return views, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *AdministratorRepo) GetSpoolerDiv(database, view string) int64 {
|
|
||||||
sequence, err := repo.View.GetCurrentSequence(database, view)
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
divDuration := time.Now().Sub(sequence.LastSuccessfulSpoolerRun)
|
|
||||||
return divDuration.Milliseconds()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *AdministratorRepo) ClearView(ctx context.Context, database, view string) error {
|
func (repo *AdministratorRepo) ClearView(ctx context.Context, database, view string) error {
|
||||||
return repo.View.ClearView(database, view)
|
return repo.View.ClearView(database, view)
|
||||||
}
|
}
|
||||||
|
@@ -67,8 +67,8 @@ func (_ *Styling) AggregateTypes() []models.AggregateType {
|
|||||||
return []models.AggregateType{org.AggregateType, instance.AggregateType}
|
return []models.AggregateType{org.AggregateType, instance.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Styling) CurrentSequence() (uint64, error) {
|
func (m *Styling) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := m.view.GetLatestStylingSequence()
|
sequence, err := m.view.GetLatestStylingSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -76,13 +76,29 @@ func (m *Styling) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *Styling) EventQuery() (*models.SearchQuery, error) {
|
func (m *Styling) EventQuery() (*models.SearchQuery, error) {
|
||||||
sequence, err := m.view.GetLatestStylingSequence()
|
sequences, err := m.view.GetLatestStylingSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return models.NewSearchQuery().
|
query := models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(m.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
AggregateTypeFilter(m.AggregateTypes()...).
|
AggregateTypeFilter(m.AggregateTypes()...).
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Styling) Reduce(event *models.Event) (err error) {
|
func (m *Styling) Reduce(event *models.Event) (err error) {
|
||||||
@@ -123,7 +139,7 @@ func (m *Styling) processLabelPolicy(event *models.Event) (err error) {
|
|||||||
org.LabelPolicyFontRemovedEventType,
|
org.LabelPolicyFontRemovedEventType,
|
||||||
instance.LabelPolicyAssetsRemovedEventType,
|
instance.LabelPolicyAssetsRemovedEventType,
|
||||||
org.LabelPolicyAssetsRemovedEventType:
|
org.LabelPolicyAssetsRemovedEventType:
|
||||||
policy, err = m.view.StylingByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
policy, err = m.view.StylingByAggregateIDAndState(event.AggregateID, event.InstanceID, int32(domain.LabelPolicyStatePreview))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -131,7 +147,7 @@ func (m *Styling) processLabelPolicy(event *models.Event) (err error) {
|
|||||||
|
|
||||||
case instance.LabelPolicyActivatedEventType,
|
case instance.LabelPolicyActivatedEventType,
|
||||||
org.LabelPolicyActivatedEventType:
|
org.LabelPolicyActivatedEventType:
|
||||||
policy, err = m.view.StylingByAggregateIDAndState(event.AggregateID, int32(domain.LabelPolicyStatePreview))
|
policy, err = m.view.StylingByAggregateIDAndState(event.AggregateID, event.InstanceID, int32(domain.LabelPolicyStatePreview))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,9 @@ package spooler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
es_locker "github.com/caos/zitadel/internal/eventstore/v1/locker"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
es_locker "github.com/caos/zitadel/internal/eventstore/v1/locker"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -14,6 +15,6 @@ type locker struct {
|
|||||||
dbClient *sql.DB
|
dbClient *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
|
func (l *locker) Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error {
|
||||||
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime)
|
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, instanceID, waitTime)
|
||||||
}
|
}
|
||||||
|
@@ -17,8 +17,8 @@ func (v *View) RemoveFailedEvent(database string, failedEvent *repository.Failed
|
|||||||
return repository.RemoveFailedEvent(v.Db, database+"."+errColumn, failedEvent)
|
return repository.RemoveFailedEvent(v.Db, database+"."+errColumn, failedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestFailedEvent(viewName string, sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) latestFailedEvent(viewName, instanceID string, sequence uint64) (*repository.FailedEvent, error) {
|
||||||
return repository.LatestFailedEvent(v.Db, errTable, viewName, sequence)
|
return repository.LatestFailedEvent(v.Db, errTable, viewName, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) AllFailedEvents(db string) ([]*repository.FailedEvent, error) {
|
func (v *View) AllFailedEvents(db string) ([]*repository.FailedEvent, error) {
|
||||||
|
@@ -12,11 +12,15 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
||||||
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.Sequence, event.CreationDate)
|
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.InstanceID, event.Sequence, event.CreationDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
|
func (v *View) latestSequence(viewName, instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return repository.LatestSequence(v.Db, sequencesTable, viewName)
|
return repository.LatestSequence(v.Db, sequencesTable, viewName, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) latestSequences(viewName string) ([]*repository.CurrentSequence, error) {
|
||||||
|
return repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) AllCurrentSequences(db string) ([]*repository.CurrentSequence, error) {
|
func (v *View) AllCurrentSequences(db string) ([]*repository.CurrentSequence, error) {
|
||||||
@@ -24,21 +28,23 @@ func (v *View) AllCurrentSequences(db string) ([]*repository.CurrentSequence, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
||||||
currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
|
currentSequences, err := repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if currentSequence.ViewName == "" {
|
for _, currentSequence := range currentSequences {
|
||||||
currentSequence.ViewName = viewName
|
if currentSequence.ViewName == "" {
|
||||||
|
currentSequence.ViewName = viewName
|
||||||
|
}
|
||||||
|
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
||||||
}
|
}
|
||||||
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
return repository.UpdateCurrentSequences(v.Db, sequencesTable, currentSequences)
|
||||||
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetCurrentSequence(db, viewName string) (*repository.CurrentSequence, error) {
|
func (v *View) GetCurrentSequence(db, viewName string) ([]*repository.CurrentSequence, error) {
|
||||||
sequenceTable := db + ".current_sequences"
|
sequenceTable := db + ".current_sequences"
|
||||||
fullView := db + "." + viewName
|
fullView := db + "." + viewName
|
||||||
return repository.LatestSequence(v.Db, sequenceTable, fullView)
|
return repository.LatestSequences(v.Db, sequenceTable, fullView)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ClearView(db, viewName string) error {
|
func (v *View) ClearView(db, viewName string) error {
|
||||||
|
@@ -11,8 +11,8 @@ const (
|
|||||||
stylingTyble = "adminapi.styling"
|
stylingTyble = "adminapi.styling"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) StylingByAggregateIDAndState(aggregateID string, state int32) (*model.LabelPolicyView, error) {
|
func (v *View) StylingByAggregateIDAndState(aggregateID, instanceID string, state int32) (*model.LabelPolicyView, error) {
|
||||||
return view.GetStylingByAggregateIDAndState(v.Db, stylingTyble, aggregateID, state)
|
return view.GetStylingByAggregateIDAndState(v.Db, stylingTyble, aggregateID, instanceID, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutStyling(policy *model.LabelPolicyView, event *models.Event) error {
|
func (v *View) PutStyling(policy *model.LabelPolicyView, event *models.Event) error {
|
||||||
@@ -23,8 +23,12 @@ func (v *View) PutStyling(policy *model.LabelPolicyView, event *models.Event) er
|
|||||||
return v.ProcessedStylingSequence(event)
|
return v.ProcessedStylingSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestStylingSequence() (*global_view.CurrentSequence, error) {
|
func (v *View) GetLatestStylingSequence(instanceID string) (*global_view.CurrentSequence, error) {
|
||||||
return v.latestSequence(stylingTyble)
|
return v.latestSequence(stylingTyble, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestStylingSequences() ([]*global_view.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(stylingTyble)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedStylingSequence(event *models.Event) error {
|
func (v *View) ProcessedStylingSequence(event *models.Event) error {
|
||||||
@@ -35,8 +39,8 @@ func (v *View) UpdateStylingSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(stylingTyble)
|
return v.updateSpoolerRunSequence(stylingTyble)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestStylingFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
func (v *View) GetLatestStylingFailedEvent(sequence uint64, instanceID string) (*global_view.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(stylingTyble, sequence)
|
return v.latestFailedEvent(stylingTyble, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedStylingFailedEvent(failedEvent *global_view.FailedEvent) error {
|
func (v *View) ProcessedStylingFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||||
|
@@ -8,13 +8,13 @@ import (
|
|||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/crypto"
|
"github.com/caos/zitadel/internal/crypto"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/query"
|
"github.com/caos/zitadel/internal/query"
|
||||||
"github.com/caos/zitadel/internal/repository/keypair"
|
"github.com/caos/zitadel/internal/repository/keypair"
|
||||||
|
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -154,7 +154,7 @@ func (o *OPStorage) lockAndGenerateSigningKeyPair(ctx context.Context, algorithm
|
|||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
errs := o.locker.Lock(ctx, o.signingKeyRotationCheck*2)
|
errs := o.locker.Lock(ctx, o.signingKeyRotationCheck*2, authz.GetInstance(ctx).InstanceID())
|
||||||
err, ok := <-errs
|
err, ok := <-errs
|
||||||
if err != nil || !ok {
|
if err != nil || !ok {
|
||||||
if errors.IsErrorAlreadyExists(err) {
|
if errors.IsErrorAlreadyExists(err) {
|
||||||
|
@@ -61,12 +61,12 @@ type privacyPolicyProvider interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type userSessionViewProvider interface {
|
type userSessionViewProvider interface {
|
||||||
UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error)
|
UserSessionByIDs(string, string, string) (*user_view_model.UserSessionView, error)
|
||||||
UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error)
|
UserSessionsByAgentID(string, string) ([]*user_view_model.UserSessionView, error)
|
||||||
PrefixAvatarURL() string
|
PrefixAvatarURL() string
|
||||||
}
|
}
|
||||||
type userViewProvider interface {
|
type userViewProvider interface {
|
||||||
UserByID(string) (*user_view_model.UserView, error)
|
UserByID(string, string) (*user_view_model.UserView, error)
|
||||||
PrefixAvatarURL() string
|
PrefixAvatarURL() string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ type lockoutPolicyViewProvider interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type idpProviderViewProvider interface {
|
type idpProviderViewProvider interface {
|
||||||
IDPProvidersByAggregateIDAndState(string, iam_model.IDPConfigState) ([]*iam_view_model.IDPProviderView, error)
|
IDPProvidersByAggregateIDAndState(string, string, iam_model.IDPConfigState) ([]*iam_view_model.IDPProviderView, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type userEventProvider interface {
|
type userEventProvider interface {
|
||||||
@@ -102,7 +102,7 @@ type userGrantProvider interface {
|
|||||||
|
|
||||||
type projectProvider interface {
|
type projectProvider interface {
|
||||||
ProjectByOIDCClientID(context.Context, string) (*query.Project, error)
|
ProjectByOIDCClientID(context.Context, string) (*query.Project, error)
|
||||||
OrgProjectMappingByIDs(orgID, projectID string) (*project_view_model.OrgProjectMapping, error)
|
OrgProjectMappingByIDs(orgID, projectID, instanceID string) (*project_view_model.OrgProjectMapping, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type applicationProvider interface {
|
type applicationProvider interface {
|
||||||
@@ -596,7 +596,7 @@ func (repo *AuthRequestRepo) fillPolicies(ctx context.Context, request *domain.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) tryUsingOnlyUserSession(request *domain.AuthRequest) error {
|
func (repo *AuthRequestRepo) tryUsingOnlyUserSession(request *domain.AuthRequest) error {
|
||||||
userSessions, err := userSessionsByUserAgentID(repo.UserSessionViewProvider, request.AgentID)
|
userSessions, err := userSessionsByUserAgentID(repo.UserSessionViewProvider, request.AgentID, request.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -618,9 +618,9 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *domain
|
|||||||
if request.RequestedOrgID != "" {
|
if request.RequestedOrgID != "" {
|
||||||
preferredLoginName += "@" + request.RequestedPrimaryDomain
|
preferredLoginName += "@" + request.RequestedPrimaryDomain
|
||||||
}
|
}
|
||||||
user, err = repo.View.UserByLoginNameAndResourceOwner(preferredLoginName, request.RequestedOrgID)
|
user, err = repo.View.UserByLoginNameAndResourceOwner(preferredLoginName, request.RequestedOrgID, request.InstanceID)
|
||||||
} else {
|
} else {
|
||||||
user, err = repo.View.UserByLoginName(loginName)
|
user, err = repo.View.UserByLoginName(loginName, request.InstanceID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = repo.checkLoginPolicyWithResourceOwner(ctx, request, user)
|
err = repo.checkLoginPolicyWithResourceOwner(ctx, request, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -696,9 +696,9 @@ func (repo *AuthRequestRepo) checkSelectedExternalIDP(request *domain.AuthReques
|
|||||||
func (repo *AuthRequestRepo) checkExternalUserLogin(ctx context.Context, request *domain.AuthRequest, idpConfigID, externalUserID string) (err error) {
|
func (repo *AuthRequestRepo) checkExternalUserLogin(ctx context.Context, request *domain.AuthRequest, idpConfigID, externalUserID string) (err error) {
|
||||||
externalIDP := new(user_view_model.ExternalIDPView)
|
externalIDP := new(user_view_model.ExternalIDPView)
|
||||||
if request.RequestedOrgID != "" {
|
if request.RequestedOrgID != "" {
|
||||||
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, request.RequestedOrgID)
|
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, request.RequestedOrgID, request.InstanceID)
|
||||||
} else {
|
} else {
|
||||||
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID)
|
externalIDP, err = repo.View.ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID, request.InstanceID)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -828,7 +828,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *AuthRequestRepo) usersForUserSelection(request *domain.AuthRequest) ([]domain.UserSelection, error) {
|
func (repo *AuthRequestRepo) usersForUserSelection(request *domain.AuthRequest) ([]domain.UserSelection, error) {
|
||||||
userSessions, err := userSessionsByUserAgentID(repo.UserSessionViewProvider, request.AgentID)
|
userSessions, err := userSessionsByUserAgentID(repo.UserSessionViewProvider, request.AgentID, request.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1044,13 +1044,13 @@ func setOrgID(orgViewProvider orgViewProvider, request *domain.AuthRequest) erro
|
|||||||
|
|
||||||
func getLoginPolicyIDPProviders(provider idpProviderViewProvider, iamID, orgID string, defaultPolicy bool) ([]*iam_model.IDPProviderView, error) {
|
func getLoginPolicyIDPProviders(provider idpProviderViewProvider, iamID, orgID string, defaultPolicy bool) ([]*iam_model.IDPProviderView, error) {
|
||||||
if defaultPolicy {
|
if defaultPolicy {
|
||||||
idpProviders, err := provider.IDPProvidersByAggregateIDAndState(iamID, iam_model.IDPConfigStateActive)
|
idpProviders, err := provider.IDPProvidersByAggregateIDAndState(iamID, iamID, iam_model.IDPConfigStateActive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return iam_view_model.IDPProviderViewsToModel(idpProviders), nil
|
return iam_view_model.IDPProviderViewsToModel(idpProviders), nil
|
||||||
}
|
}
|
||||||
idpProviders, err := provider.IDPProvidersByAggregateIDAndState(orgID, iam_model.IDPConfigStateActive)
|
idpProviders, err := provider.IDPProvidersByAggregateIDAndState(orgID, iamID, iam_model.IDPConfigStateActive)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1071,8 +1071,8 @@ func checkVerificationTime(verificationTime time.Time, lifetime time.Duration) b
|
|||||||
return verificationTime.Add(lifetime).After(time.Now().UTC())
|
return verificationTime.Add(lifetime).After(time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
func userSessionsByUserAgentID(provider userSessionViewProvider, agentID string) ([]*user_model.UserSessionView, error) {
|
func userSessionsByUserAgentID(provider userSessionViewProvider, agentID, instanceID string) ([]*user_model.UserSessionView, error) {
|
||||||
session, err := provider.UserSessionsByAgentID(agentID)
|
session, err := provider.UserSessionsByAgentID(agentID, instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1080,7 +1080,7 @@ func userSessionsByUserAgentID(provider userSessionViewProvider, agentID string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eventProvider userEventProvider, agentID string, user *user_model.UserView) (*user_model.UserSessionView, error) {
|
func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eventProvider userEventProvider, agentID string, user *user_model.UserView) (*user_model.UserSessionView, error) {
|
||||||
session, err := provider.UserSessionByIDs(agentID, user.ID)
|
session, err := provider.UserSessionByIDs(agentID, user.ID, authz.GetInstance(ctx).InstanceID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1156,7 +1156,7 @@ func activeUserByID(ctx context.Context, userViewProvider userViewProvider, user
|
|||||||
}
|
}
|
||||||
|
|
||||||
func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider userEventProvider, userID string) (*user_model.UserView, error) {
|
func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider userEventProvider, userID string) (*user_model.UserView, error) {
|
||||||
user, viewErr := viewProvider.UserByID(userID)
|
user, viewErr := viewProvider.UserByID(userID, authz.GetInstance(ctx).InstanceID())
|
||||||
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
||||||
return nil, viewErr
|
return nil, viewErr
|
||||||
} else if user == nil {
|
} else if user == nil {
|
||||||
@@ -1254,7 +1254,7 @@ func projectRequired(ctx context.Context, request *domain.AuthRequest, projectPr
|
|||||||
if !project.HasProjectCheck {
|
if !project.HasProjectCheck {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
_, err = projectProvider.OrgProjectMappingByIDs(request.UserOrgID, project.ID)
|
_, err = projectProvider.OrgProjectMappingByIDs(request.UserOrgID, project.ID, request.InstanceID)
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@@ -24,11 +24,11 @@ import (
|
|||||||
|
|
||||||
type mockViewNoUserSession struct{}
|
type mockViewNoUserSession struct{}
|
||||||
|
|
||||||
func (m *mockViewNoUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
|
func (m *mockViewNoUserSession) UserSessionByIDs(string, string, string) (*user_view_model.UserSessionView, error) {
|
||||||
return nil, errors.ThrowNotFound(nil, "id", "user session not found")
|
return nil, errors.ThrowNotFound(nil, "id", "user session not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockViewNoUserSession) UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error) {
|
func (m *mockViewNoUserSession) UserSessionsByAgentID(string, string) ([]*user_view_model.UserSessionView, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,11 +38,11 @@ func (m *mockViewNoUserSession) PrefixAvatarURL() string {
|
|||||||
|
|
||||||
type mockViewErrUserSession struct{}
|
type mockViewErrUserSession struct{}
|
||||||
|
|
||||||
func (m *mockViewErrUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
|
func (m *mockViewErrUserSession) UserSessionByIDs(string, string, string) (*user_view_model.UserSessionView, error) {
|
||||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error) {
|
func (m *mockViewErrUserSession) UserSessionsByAgentID(string, string) ([]*user_view_model.UserSessionView, error) {
|
||||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ type mockUser struct {
|
|||||||
ResourceOwner string
|
ResourceOwner string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
|
func (m *mockViewUserSession) UserSessionByIDs(string, string, string) (*user_view_model.UserSessionView, error) {
|
||||||
return &user_view_model.UserSessionView{
|
return &user_view_model.UserSessionView{
|
||||||
ExternalLoginVerification: m.ExternalLoginVerification,
|
ExternalLoginVerification: m.ExternalLoginVerification,
|
||||||
PasswordlessVerification: m.PasswordlessVerification,
|
PasswordlessVerification: m.PasswordlessVerification,
|
||||||
@@ -75,7 +75,7 @@ func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockViewUserSession) UserSessionsByAgentID(string) ([]*user_view_model.UserSessionView, error) {
|
func (m *mockViewUserSession) UserSessionsByAgentID(string, string) ([]*user_view_model.UserSessionView, error) {
|
||||||
sessions := make([]*user_view_model.UserSessionView, len(m.Users))
|
sessions := make([]*user_view_model.UserSessionView, len(m.Users))
|
||||||
for i, user := range m.Users {
|
for i, user := range m.Users {
|
||||||
sessions[i] = &user_view_model.UserSessionView{
|
sessions[i] = &user_view_model.UserSessionView{
|
||||||
@@ -93,7 +93,7 @@ func (m *mockViewUserSession) PrefixAvatarURL() string {
|
|||||||
|
|
||||||
type mockViewNoUser struct{}
|
type mockViewNoUser struct{}
|
||||||
|
|
||||||
func (m *mockViewNoUser) UserByID(string) (*user_view_model.UserView, error) {
|
func (m *mockViewNoUser) UserByID(string, string) (*user_view_model.UserView, error) {
|
||||||
return nil, errors.ThrowNotFound(nil, "id", "user not found")
|
return nil, errors.ThrowNotFound(nil, "id", "user not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ func (m *mockLockoutPolicy) LockoutPolicyByOrg(context.Context, string) (*query.
|
|||||||
return m.policy, nil
|
return m.policy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockViewUser) UserByID(string) (*user_view_model.UserView, error) {
|
func (m *mockViewUser) UserByID(string, string) (*user_view_model.UserView, error) {
|
||||||
return &user_view_model.UserView{
|
return &user_view_model.UserView{
|
||||||
State: int32(user_model.UserStateActive),
|
State: int32(user_model.UserStateActive),
|
||||||
UserName: "UserName",
|
UserName: "UserName",
|
||||||
@@ -232,7 +232,7 @@ func (m *mockProject) ProjectByOIDCClientID(ctx context.Context, s string) (*que
|
|||||||
return &query.Project{HasProjectCheck: m.projectCheck}, nil
|
return &query.Project{HasProjectCheck: m.projectCheck}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockProject) OrgProjectMappingByIDs(orgID, projectID string) (*proj_view_model.OrgProjectMapping, error) {
|
func (m *mockProject) OrgProjectMappingByIDs(orgID, projectID, instanceID string) (*proj_view_model.OrgProjectMapping, error) {
|
||||||
if m.hasProject {
|
if m.hasProject {
|
||||||
return &proj_view_model.OrgProjectMapping{OrgID: orgID, ProjectID: projectID}, nil
|
return &proj_view_model.OrgProjectMapping{OrgID: orgID, ProjectID: projectID}, nil
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ type OrgRepository struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *OrgRepository) GetIDPConfigByID(ctx context.Context, idpConfigID string) (*iam_model.IDPConfigView, error) {
|
func (repo *OrgRepository) GetIDPConfigByID(ctx context.Context, idpConfigID string) (*iam_model.IDPConfigView, error) {
|
||||||
idpConfig, err := repo.View.IDPConfigByID(idpConfigID)
|
idpConfig, err := repo.View.IDPConfigByID(idpConfigID, authz.GetInstance(ctx).InstanceID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -6,16 +6,16 @@ import (
|
|||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/crypto"
|
"github.com/caos/zitadel/internal/crypto"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
usr_view "github.com/caos/zitadel/internal/user/repository/view"
|
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
|
||||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||||
|
usr_view "github.com/caos/zitadel/internal/user/repository/view"
|
||||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func (r *RefreshTokenRepo) RefreshTokenByID(ctx context.Context, refreshToken st
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tokenView, viewErr := r.View.RefreshTokenByID(tokenID)
|
tokenView, viewErr := r.View.RefreshTokenByID(tokenID, authz.GetInstance(ctx).InstanceID())
|
||||||
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
||||||
return nil, viewErr
|
return nil, viewErr
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ func (r *RefreshTokenRepo) RefreshTokenByID(ctx context.Context, refreshToken st
|
|||||||
tokenView.UserID = userID
|
tokenView.UserID = userID
|
||||||
}
|
}
|
||||||
|
|
||||||
events, esErr := r.getUserEvents(ctx, userID, tokenView.Sequence)
|
events, esErr := r.getUserEvents(ctx, userID, tokenView.InstanceID, tokenView.Sequence)
|
||||||
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
||||||
return nil, errors.ThrowNotFound(nil, "EVENT-BHB52", "Errors.User.RefreshToken.Invalid")
|
return nil, errors.ThrowNotFound(nil, "EVENT-BHB52", "Errors.User.RefreshToken.Invalid")
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ func (r *RefreshTokenRepo) SearchMyRefreshTokens(ctx context.Context, userID str
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sequence, err := r.View.GetLatestRefreshTokenSequence()
|
sequence, err := r.View.GetLatestRefreshTokenSequence(authz.GetInstance(ctx).InstanceID())
|
||||||
logging.Log("EVENT-GBdn4").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest refresh token sequence")
|
logging.Log("EVENT-GBdn4").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Warn("could not read latest refresh token sequence")
|
||||||
request.Queries = append(request.Queries, &usr_model.RefreshTokenSearchQuery{Key: usr_model.RefreshTokenSearchKeyUserID, Method: domain.SearchMethodEquals, Value: userID})
|
request.Queries = append(request.Queries, &usr_model.RefreshTokenSearchQuery{Key: usr_model.RefreshTokenSearchKeyUserID, Method: domain.SearchMethodEquals, Value: userID})
|
||||||
tokens, count, err := r.View.SearchRefreshTokens(request)
|
tokens, count, err := r.View.SearchRefreshTokens(request)
|
||||||
@@ -85,8 +85,8 @@ func (r *RefreshTokenRepo) SearchMyRefreshTokens(ctx context.Context, userID str
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RefreshTokenRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) {
|
func (r *RefreshTokenRepo) getUserEvents(ctx context.Context, userID, instanceID string, sequence uint64) ([]*models.Event, error) {
|
||||||
query, err := usr_view.UserByIDQuery(userID, sequence)
|
query, err := usr_view.UserByIDQuery(userID, instanceID, sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -2,18 +2,18 @@ package eventstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
|
||||||
usr_view "github.com/caos/zitadel/internal/user/repository/view"
|
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||||
usr_model "github.com/caos/zitadel/internal/user/model"
|
usr_model "github.com/caos/zitadel/internal/user/model"
|
||||||
|
usr_view "github.com/caos/zitadel/internal/user/repository/view"
|
||||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ func (repo *TokenRepo) IsTokenValid(ctx context.Context, userID, tokenID string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *TokenRepo) TokenByID(ctx context.Context, userID, tokenID string) (*usr_model.TokenView, error) {
|
func (repo *TokenRepo) TokenByID(ctx context.Context, userID, tokenID string) (*usr_model.TokenView, error) {
|
||||||
token, viewErr := repo.View.TokenByID(tokenID)
|
token, viewErr := repo.View.TokenByID(tokenID, authz.GetInstance(ctx).InstanceID())
|
||||||
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
if viewErr != nil && !errors.IsNotFound(viewErr) {
|
||||||
return nil, viewErr
|
return nil, viewErr
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ func (repo *TokenRepo) TokenByID(ctx context.Context, userID, tokenID string) (*
|
|||||||
token.UserID = userID
|
token.UserID = userID
|
||||||
}
|
}
|
||||||
|
|
||||||
events, esErr := repo.getUserEvents(ctx, userID, token.Sequence)
|
events, esErr := repo.getUserEvents(ctx, userID, token.InstanceID, token.Sequence)
|
||||||
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
if errors.IsNotFound(viewErr) && len(events) == 0 {
|
||||||
return nil, errors.ThrowNotFound(nil, "EVENT-4T90g", "Errors.Token.NotFound")
|
return nil, errors.ThrowNotFound(nil, "EVENT-4T90g", "Errors.Token.NotFound")
|
||||||
}
|
}
|
||||||
@@ -66,8 +66,8 @@ func (repo *TokenRepo) TokenByID(ctx context.Context, userID, tokenID string) (*
|
|||||||
return model.TokenViewToModel(token), nil
|
return model.TokenViewToModel(token), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *TokenRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) {
|
func (r *TokenRepo) getUserEvents(ctx context.Context, userID, instanceID string, sequence uint64) ([]*models.Event, error) {
|
||||||
query, err := usr_view.UserByIDQuery(userID, sequence)
|
query, err := usr_view.UserByIDQuery(userID, instanceID, sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package eventstore
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
@@ -26,7 +27,7 @@ func (repo *UserRepo) Health(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *UserRepo) UserSessionUserIDsByAgentID(ctx context.Context, agentID string) ([]string, error) {
|
func (repo *UserRepo) UserSessionUserIDsByAgentID(ctx context.Context, agentID string) ([]string, error) {
|
||||||
userSessions, err := repo.View.UserSessionsByAgentID(agentID)
|
userSessions, err := repo.View.UserSessionsByAgentID(agentID, authz.GetInstance(ctx).InstanceID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -44,7 +45,7 @@ func (repo *UserRepo) UserEventsByID(ctx context.Context, id string, sequence ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *UserRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) {
|
func (r *UserRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) {
|
||||||
query, err := usr_view.UserByIDQuery(userID, sequence)
|
query, err := usr_view.UserByIDQuery(userID, authz.GetInstance(ctx).InstanceID(), sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ type UserSessionRepo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_model.UserSessionView, error) {
|
func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_model.UserSessionView, error) {
|
||||||
userSessions, err := repo.View.UserSessionsByAgentID(authz.GetCtxData(ctx).AgentID)
|
userSessions, err := repo.View.UserSessionsByAgentID(authz.GetCtxData(ctx).AgentID, authz.GetInstance(ctx).InstanceID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -54,8 +54,8 @@ func (_ *IDPConfig) AggregateTypes() []models.AggregateType {
|
|||||||
return []models.AggregateType{org.AggregateType, instance.AggregateType}
|
return []models.AggregateType{org.AggregateType, instance.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IDPConfig) CurrentSequence() (uint64, error) {
|
func (i *IDPConfig) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := i.view.GetLatestIDPConfigSequence()
|
sequence, err := i.view.GetLatestIDPConfigSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -63,13 +63,30 @@ func (i *IDPConfig) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
|
func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
|
||||||
sequence, err := i.view.GetLatestIDPConfigSequence()
|
sequences, err := i.view.GetLatestIDPConfigSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return models.NewSearchQuery().
|
|
||||||
|
query := models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(i.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
AggregateTypeFilter(i.AggregateTypes()...).
|
AggregateTypeFilter(i.AggregateTypes()...).
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IDPConfig) Reduce(event *models.Event) (err error) {
|
func (i *IDPConfig) Reduce(event *models.Event) (err error) {
|
||||||
@@ -97,7 +114,7 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
idp, err = i.view.IDPConfigByID(idp.IDPConfigID)
|
idp, err = i.view.IDPConfigByID(idp.IDPConfigID, idp.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -108,7 +125,7 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
idp, err = i.view.IDPConfigByID(idp.IDPConfigID)
|
idp, err = i.view.IDPConfigByID(idp.IDPConfigID, idp.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
@@ -67,8 +68,8 @@ func (_ *IDPProvider) AggregateTypes() []models.AggregateType {
|
|||||||
return []es_models.AggregateType{instance.AggregateType, org.AggregateType}
|
return []es_models.AggregateType{instance.AggregateType, org.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IDPProvider) CurrentSequence() (uint64, error) {
|
func (i *IDPProvider) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := i.view.GetLatestIDPProviderSequence()
|
sequence, err := i.view.GetLatestIDPProviderSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -76,13 +77,29 @@ func (i *IDPProvider) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
|
func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
|
||||||
sequence, err := i.view.GetLatestIDPProviderSequence()
|
sequences, err := i.view.GetLatestIDPProviderSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return es_models.NewSearchQuery().
|
query := es_models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(i.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
AggregateTypeFilter(i.AggregateTypes()...).
|
AggregateTypeFilter(i.AggregateTypes()...).
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *IDPProvider) Reduce(event *models.Event) (err error) {
|
func (i *IDPProvider) Reduce(event *models.Event) (err error) {
|
||||||
@@ -108,7 +125,7 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event)
|
return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.InstanceID, event)
|
||||||
case instance.IDPConfigChangedEventType, org.IDPConfigChangedEventType:
|
case instance.IDPConfigChangedEventType, org.IDPConfigChangedEventType:
|
||||||
esConfig := new(iam_view_model.IDPConfigView)
|
esConfig := new(iam_view_model.IDPConfigView)
|
||||||
providerType := iam_model.IDPProviderTypeSystem
|
providerType := iam_model.IDPProviderTypeSystem
|
||||||
@@ -116,7 +133,7 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
|
|||||||
providerType = iam_model.IDPProviderTypeOrg
|
providerType = iam_model.IDPProviderTypeOrg
|
||||||
}
|
}
|
||||||
esConfig.AppendEvent(providerType, event)
|
esConfig.AppendEvent(providerType, event)
|
||||||
providers, err := i.view.IDPProvidersByIDPConfigID(esConfig.IDPConfigID)
|
providers, err := i.view.IDPProvidersByIDPConfigID(esConfig.IDPConfigID, esConfig.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -134,7 +151,7 @@ func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
return i.view.PutIDPProviders(event, providers...)
|
return i.view.PutIDPProviders(event, providers...)
|
||||||
case org.LoginPolicyRemovedEventType:
|
case org.LoginPolicyRemovedEventType:
|
||||||
return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event)
|
return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return i.view.ProcessedIDPProviderSequence(event)
|
return i.view.ProcessedIDPProviderSequence(event)
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,6 @@ import (
|
|||||||
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||||
proj_view "github.com/caos/zitadel/internal/project/repository/view"
|
|
||||||
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
|
||||||
"github.com/caos/zitadel/internal/repository/project"
|
"github.com/caos/zitadel/internal/repository/project"
|
||||||
)
|
)
|
||||||
@@ -55,8 +54,8 @@ func (_ *OrgProjectMapping) AggregateTypes() []es_models.AggregateType {
|
|||||||
return []es_models.AggregateType{project.AggregateType}
|
return []es_models.AggregateType{project.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *OrgProjectMapping) CurrentSequence() (uint64, error) {
|
func (p *OrgProjectMapping) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := p.view.GetLatestOrgProjectMappingSequence()
|
sequence, err := p.view.GetLatestOrgProjectMappingSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -64,11 +63,29 @@ func (p *OrgProjectMapping) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *OrgProjectMapping) EventQuery() (*es_models.SearchQuery, error) {
|
func (p *OrgProjectMapping) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
sequence, err := p.view.GetLatestOrgProjectMappingSequence()
|
sequences, err := p.view.GetLatestOrgProjectMappingSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return proj_view.ProjectQuery(sequence.CurrentSequence), nil
|
query := es_models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(p.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
|
AggregateTypeFilter(p.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *OrgProjectMapping) Reduce(event *es_models.Event) (err error) {
|
func (p *OrgProjectMapping) Reduce(event *es_models.Event) (err error) {
|
||||||
@@ -79,7 +96,7 @@ func (p *OrgProjectMapping) Reduce(event *es_models.Event) (err error) {
|
|||||||
mapping.ProjectID = event.AggregateID
|
mapping.ProjectID = event.AggregateID
|
||||||
mapping.InstanceID = event.InstanceID
|
mapping.InstanceID = event.InstanceID
|
||||||
case project.ProjectRemovedType:
|
case project.ProjectRemovedType:
|
||||||
err := p.view.DeleteOrgProjectMappingsByProjectID(event.AggregateID)
|
err := p.view.DeleteOrgProjectMappingsByProjectID(event.AggregateID, event.InstanceID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return p.view.ProcessedOrgProjectMappingSequence(event)
|
return p.view.ProcessedOrgProjectMappingSequence(event)
|
||||||
}
|
}
|
||||||
@@ -93,7 +110,7 @@ func (p *OrgProjectMapping) Reduce(event *es_models.Event) (err error) {
|
|||||||
case project.GrantRemovedType:
|
case project.GrantRemovedType:
|
||||||
projectGrant := new(view_model.ProjectGrant)
|
projectGrant := new(view_model.ProjectGrant)
|
||||||
projectGrant.SetData(event)
|
projectGrant.SetData(event)
|
||||||
err := p.view.DeleteOrgProjectMappingsByProjectGrantID(event.AggregateID)
|
err := p.view.DeleteOrgProjectMappingsByProjectGrantID(event.AggregateID, event.InstanceID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return p.view.ProcessedOrgProjectMappingSequence(event)
|
return p.view.ProcessedOrgProjectMappingSequence(event)
|
||||||
}
|
}
|
||||||
|
@@ -58,8 +58,8 @@ func (t *RefreshToken) AggregateTypes() []es_models.AggregateType {
|
|||||||
return []es_models.AggregateType{user.AggregateType, project.AggregateType}
|
return []es_models.AggregateType{user.AggregateType, project.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *RefreshToken) CurrentSequence() (uint64, error) {
|
func (t *RefreshToken) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := t.view.GetLatestRefreshTokenSequence()
|
sequence, err := t.view.GetLatestRefreshTokenSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -67,13 +67,29 @@ func (t *RefreshToken) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *RefreshToken) EventQuery() (*es_models.SearchQuery, error) {
|
func (t *RefreshToken) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
sequence, err := t.view.GetLatestRefreshTokenSequence()
|
sequences, err := t.view.GetLatestRefreshTokenSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return es_models.NewSearchQuery().
|
query := es_models.NewSearchQuery()
|
||||||
AggregateTypeFilter(user.AggregateType, project.AggregateType).
|
instances := make([]string, 0)
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(t.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
|
AggregateTypeFilter(t.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *RefreshToken) Reduce(event *es_models.Event) (err error) {
|
func (t *RefreshToken) Reduce(event *es_models.Event) (err error) {
|
||||||
@@ -91,7 +107,7 @@ func (t *RefreshToken) Reduce(event *es_models.Event) (err error) {
|
|||||||
logging.Log("EVEN-DBbn4").WithError(err).Error("could not unmarshal event data")
|
logging.Log("EVEN-DBbn4").WithError(err).Error("could not unmarshal event data")
|
||||||
return caos_errs.ThrowInternal(nil, "MODEL-BHn75", "could not unmarshal data")
|
return caos_errs.ThrowInternal(nil, "MODEL-BHn75", "could not unmarshal data")
|
||||||
}
|
}
|
||||||
token, err := t.view.RefreshTokenByID(e.TokenID)
|
token, err := t.view.RefreshTokenByID(e.TokenID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -106,11 +122,11 @@ func (t *RefreshToken) Reduce(event *es_models.Event) (err error) {
|
|||||||
logging.Log("EVEN-BDbh3").WithError(err).Error("could not unmarshal event data")
|
logging.Log("EVEN-BDbh3").WithError(err).Error("could not unmarshal event data")
|
||||||
return caos_errs.ThrowInternal(nil, "MODEL-Bz653", "could not unmarshal data")
|
return caos_errs.ThrowInternal(nil, "MODEL-Bz653", "could not unmarshal data")
|
||||||
}
|
}
|
||||||
return t.view.DeleteRefreshToken(e.TokenID, event)
|
return t.view.DeleteRefreshToken(e.TokenID, event.InstanceID, event)
|
||||||
case user.UserLockedType,
|
case user.UserLockedType,
|
||||||
user.UserDeactivatedType,
|
user.UserDeactivatedType,
|
||||||
user.UserRemovedType:
|
user.UserRemovedType:
|
||||||
return t.view.DeleteUserRefreshTokens(event.AggregateID, event)
|
return t.view.DeleteUserRefreshTokens(event.AggregateID, event.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return t.view.ProcessedRefreshTokenSequence(event)
|
return t.view.ProcessedRefreshTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
@@ -64,8 +64,8 @@ func (_ *Token) AggregateTypes() []es_models.AggregateType {
|
|||||||
return []es_models.AggregateType{user.AggregateType, project.AggregateType}
|
return []es_models.AggregateType{user.AggregateType, project.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Token) CurrentSequence() (uint64, error) {
|
func (p *Token) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := p.view.GetLatestTokenSequence()
|
sequence, err := p.view.GetLatestTokenSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -73,13 +73,29 @@ func (p *Token) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) EventQuery() (*es_models.SearchQuery, error) {
|
func (t *Token) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
sequence, err := t.view.GetLatestTokenSequence()
|
sequences, err := t.view.GetLatestTokenSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return es_models.NewSearchQuery().
|
query := es_models.NewSearchQuery()
|
||||||
AggregateTypeFilter(user.AggregateType, project.AggregateType).
|
instances := make([]string, 0)
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(t.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
|
AggregateTypeFilter(t.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) Reduce(event *es_models.Event) (err error) {
|
func (t *Token) Reduce(event *es_models.Event) (err error) {
|
||||||
@@ -96,7 +112,7 @@ func (t *Token) Reduce(event *es_models.Event) (err error) {
|
|||||||
user.HumanProfileChangedType:
|
user.HumanProfileChangedType:
|
||||||
user := new(view_model.UserView)
|
user := new(view_model.UserView)
|
||||||
user.AppendEvent(event)
|
user.AppendEvent(event)
|
||||||
tokens, err := t.view.TokensByUserID(event.AggregateID)
|
tokens, err := t.view.TokensByUserID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -110,24 +126,24 @@ func (t *Token) Reduce(event *es_models.Event) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.view.DeleteSessionTokens(id, event.AggregateID, event)
|
return t.view.DeleteSessionTokens(id, event.AggregateID, event.InstanceID, event)
|
||||||
case user.UserLockedType,
|
case user.UserLockedType,
|
||||||
user.UserDeactivatedType,
|
user.UserDeactivatedType,
|
||||||
user.UserRemovedType:
|
user.UserRemovedType:
|
||||||
return t.view.DeleteUserTokens(event.AggregateID, event)
|
return t.view.DeleteUserTokens(event.AggregateID, event.InstanceID, event)
|
||||||
case user_repo.UserTokenRemovedType,
|
case user_repo.UserTokenRemovedType,
|
||||||
user_repo.PersonalAccessTokenRemovedType:
|
user_repo.PersonalAccessTokenRemovedType:
|
||||||
id, err := tokenIDFromRemovedEvent(event)
|
id, err := tokenIDFromRemovedEvent(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.view.DeleteToken(id, event)
|
return t.view.DeleteToken(id, event.InstanceID, event)
|
||||||
case user_repo.HumanRefreshTokenRemovedType:
|
case user_repo.HumanRefreshTokenRemovedType:
|
||||||
id, err := refreshTokenIDFromRemovedEvent(event)
|
id, err := refreshTokenIDFromRemovedEvent(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return t.view.DeleteTokensFromRefreshToken(id, event)
|
return t.view.DeleteTokensFromRefreshToken(id, event.InstanceID, event)
|
||||||
case project.ApplicationDeactivatedType,
|
case project.ApplicationDeactivatedType,
|
||||||
project.ApplicationRemovedType:
|
project.ApplicationRemovedType:
|
||||||
application, err := applicationFromSession(event)
|
application, err := applicationFromSession(event)
|
||||||
@@ -137,7 +153,7 @@ func (t *Token) Reduce(event *es_models.Event) (err error) {
|
|||||||
return t.view.DeleteApplicationTokens(event, application.AppID)
|
return t.view.DeleteApplicationTokens(event, application.AppID)
|
||||||
case project.ProjectDeactivatedType,
|
case project.ProjectDeactivatedType,
|
||||||
project.ProjectRemovedType:
|
project.ProjectRemovedType:
|
||||||
project, err := t.getProjectByID(context.Background(), event.AggregateID)
|
project, err := t.getProjectByID(context.Background(), event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -196,8 +212,8 @@ func (t *Token) OnSuccess() error {
|
|||||||
return spooler.HandleSuccess(t.view.UpdateTokenSpoolerRunTimestamp)
|
return spooler.HandleSuccess(t.view.UpdateTokenSpoolerRunTimestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) {
|
func (t *Token) getProjectByID(ctx context.Context, projID, instanceID string) (*proj_model.Project, error) {
|
||||||
query, err := proj_view.ProjectByIDQuery(projID, 0)
|
query, err := proj_view.ProjectByIDQuery(projID, instanceID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -65,8 +65,8 @@ func (_ *User) AggregateTypes() []es_models.AggregateType {
|
|||||||
return []es_models.AggregateType{user_repo.AggregateType, org.AggregateType}
|
return []es_models.AggregateType{user_repo.AggregateType, org.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) CurrentSequence() (uint64, error) {
|
func (u *User) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := u.view.GetLatestUserSequence()
|
sequence, err := u.view.GetLatestUserSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -74,13 +74,29 @@ func (u *User) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) EventQuery() (*es_models.SearchQuery, error) {
|
func (u *User) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
sequence, err := u.view.GetLatestUserSequence()
|
sequences, err := u.view.GetLatestUserSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return es_models.NewSearchQuery().
|
query := es_models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(u.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
AggregateTypeFilter(u.AggregateTypes()...).
|
AggregateTypeFilter(u.AggregateTypes()...).
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) Reduce(event *es_models.Event) (err error) {
|
func (u *User) Reduce(event *es_models.Event) (err error) {
|
||||||
@@ -146,14 +162,14 @@ func (u *User) ProcessUser(event *es_models.Event) (err error) {
|
|||||||
user_repo.HumanPasswordChangedType,
|
user_repo.HumanPasswordChangedType,
|
||||||
user_repo.HumanPasswordlessInitCodeAddedType,
|
user_repo.HumanPasswordlessInitCodeAddedType,
|
||||||
user_repo.HumanPasswordlessInitCodeRequestedType:
|
user_repo.HumanPasswordlessInitCodeRequestedType:
|
||||||
user, err = u.view.UserByID(event.AggregateID)
|
user, err = u.view.UserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = user.AppendEvent(event)
|
err = user.AppendEvent(event)
|
||||||
case user_repo.UserDomainClaimedType,
|
case user_repo.UserDomainClaimedType,
|
||||||
user_repo.UserUserNameChangedType:
|
user_repo.UserUserNameChangedType:
|
||||||
user, err = u.view.UserByID(event.AggregateID)
|
user, err = u.view.UserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -163,7 +179,7 @@ func (u *User) ProcessUser(event *es_models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
err = u.fillLoginNames(user)
|
err = u.fillLoginNames(user)
|
||||||
case user_repo.UserRemovedType:
|
case user_repo.UserRemovedType:
|
||||||
return u.view.DeleteUser(event.AggregateID, event)
|
return u.view.DeleteUser(event.AggregateID, event.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return u.view.ProcessedUserSequence(event)
|
return u.view.ProcessedUserSequence(event)
|
||||||
}
|
}
|
||||||
@@ -203,7 +219,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
users, err := u.view.UsersByOrgID(event.AggregateID)
|
users, err := u.view.UsersByOrgID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -221,7 +237,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) error {
|
|||||||
if !userLoginMustBeDomain {
|
if !userLoginMustBeDomain {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
users, err := u.view.UsersByOrgID(event.AggregateID)
|
users, err := u.view.UsersByOrgID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -69,8 +69,8 @@ func (_ *ExternalIDP) AggregateTypes() []es_models.AggregateType {
|
|||||||
return []es_models.AggregateType{user.AggregateType, instance.AggregateType, org.AggregateType}
|
return []es_models.AggregateType{user.AggregateType, instance.AggregateType, org.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ExternalIDP) CurrentSequence() (uint64, error) {
|
func (i *ExternalIDP) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := i.view.GetLatestExternalIDPSequence()
|
sequence, err := i.view.GetLatestExternalIDPSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -78,13 +78,29 @@ func (i *ExternalIDP) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *ExternalIDP) EventQuery() (*es_models.SearchQuery, error) {
|
func (i *ExternalIDP) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
sequence, err := i.view.GetLatestExternalIDPSequence()
|
sequences, err := i.view.GetLatestExternalIDPSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return es_models.NewSearchQuery().
|
query := es_models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(i.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
AggregateTypeFilter(i.AggregateTypes()...).
|
AggregateTypeFilter(i.AggregateTypes()...).
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ExternalIDP) Reduce(event *es_models.Event) (err error) {
|
func (i *ExternalIDP) Reduce(event *es_models.Event) (err error) {
|
||||||
@@ -111,9 +127,9 @@ func (i *ExternalIDP) processUser(event *es_models.Event) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event)
|
return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, externalIDP.InstanceID, event)
|
||||||
case user.UserRemovedType:
|
case user.UserRemovedType:
|
||||||
return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event)
|
return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return i.view.ProcessedExternalIDPSequence(event)
|
return i.view.ProcessedExternalIDPSequence(event)
|
||||||
}
|
}
|
||||||
@@ -133,7 +149,7 @@ func (i *ExternalIDP) processIdpConfig(event *es_models.Event) (err error) {
|
|||||||
} else {
|
} else {
|
||||||
configView.AppendEvent(iam_model.IDPProviderTypeOrg, event)
|
configView.AppendEvent(iam_model.IDPProviderTypeOrg, event)
|
||||||
}
|
}
|
||||||
exterinalIDPs, err := i.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
|
exterinalIDPs, err := i.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID, configView.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
"github.com/caos/zitadel/internal/eventstore/v1/spooler"
|
||||||
"github.com/caos/zitadel/internal/repository/user"
|
"github.com/caos/zitadel/internal/repository/user"
|
||||||
"github.com/caos/zitadel/internal/user/repository/view"
|
|
||||||
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,8 +56,8 @@ func (_ *UserSession) AggregateTypes() []models.AggregateType {
|
|||||||
return []models.AggregateType{user.AggregateType}
|
return []models.AggregateType{user.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserSession) CurrentSequence() (uint64, error) {
|
func (u *UserSession) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := u.view.GetLatestUserSessionSequence()
|
sequence, err := u.view.GetLatestUserSessionSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -66,11 +65,29 @@ func (u *UserSession) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserSession) EventQuery() (*models.SearchQuery, error) {
|
func (u *UserSession) EventQuery() (*models.SearchQuery, error) {
|
||||||
sequence, err := u.view.GetLatestUserSessionSequence()
|
sequences, err := u.view.GetLatestUserSessionSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return view.UserQuery(sequence.CurrentSequence), nil
|
query := models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(u.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
|
AggregateTypeFilter(u.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserSession) Reduce(event *models.Event) (err error) {
|
func (u *UserSession) Reduce(event *models.Event) (err error) {
|
||||||
@@ -95,7 +112,7 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
session, err = u.view.UserSessionByIDs(eventData.UserAgentID, event.AggregateID)
|
session, err = u.view.UserSessionByIDs(eventData.UserAgentID, event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.IsNotFound(err) {
|
if !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
@@ -126,7 +143,7 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
|
|||||||
user.UserIDPLinkCascadeRemovedType,
|
user.UserIDPLinkCascadeRemovedType,
|
||||||
user.HumanPasswordlessTokenRemovedType,
|
user.HumanPasswordlessTokenRemovedType,
|
||||||
user.HumanU2FTokenRemovedType:
|
user.HumanU2FTokenRemovedType:
|
||||||
sessions, err := u.view.UserSessionsByUserID(event.AggregateID)
|
sessions, err := u.view.UserSessionsByUserID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -143,7 +160,7 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
return u.view.PutUserSessions(sessions, event)
|
return u.view.PutUserSessions(sessions, event)
|
||||||
case user.UserRemovedType:
|
case user.UserRemovedType:
|
||||||
return u.view.DeleteUserSessions(event.AggregateID, event)
|
return u.view.DeleteUserSessions(event.AggregateID, event.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return u.view.ProcessedUserSessionSequence(event)
|
return u.view.ProcessedUserSessionSequence(event)
|
||||||
}
|
}
|
||||||
@@ -169,7 +186,7 @@ func (u *UserSession) updateSession(session *view_model.UserSessionView, event *
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error {
|
func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error {
|
||||||
user, err := u.view.UserByID(id)
|
user, err := u.view.UserByID(id, session.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,6 @@ func NewLocker(client *sql.DB) *locker {
|
|||||||
return &locker{dbClient: client}
|
return &locker{dbClient: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
|
func (l *locker) Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error {
|
||||||
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime)
|
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, instanceID, waitTime)
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,6 @@ func (v *View) saveFailedEvent(failedEvent *repository.FailedEvent) error {
|
|||||||
return repository.SaveFailedEvent(v.Db, errTable, failedEvent)
|
return repository.SaveFailedEvent(v.Db, errTable, failedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestFailedEvent(viewName string, sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) latestFailedEvent(viewName, instanceID string, sequence uint64) (*repository.FailedEvent, error) {
|
||||||
return repository.LatestFailedEvent(v.Db, errTable, viewName, sequence)
|
return repository.LatestFailedEvent(v.Db, errTable, viewName, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
@@ -12,16 +12,16 @@ const (
|
|||||||
externalIDPTable = "auth.user_external_idps"
|
externalIDPTable = "auth.user_external_idps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID string) (*model.ExternalIDPView, error) {
|
func (v *View) ExternalIDPByExternalUserIDAndIDPConfigID(externalUserID, idpConfigID, instanceID string) (*model.ExternalIDPView, error) {
|
||||||
return view.ExternalIDPByExternalUserIDAndIDPConfigID(v.Db, externalIDPTable, externalUserID, idpConfigID)
|
return view.ExternalIDPByExternalUserIDAndIDPConfigID(v.Db, externalIDPTable, externalUserID, idpConfigID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, resourceOwner string) (*model.ExternalIDPView, error) {
|
func (v *View) ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(externalUserID, idpConfigID, resourceOwner, instanceID string) (*model.ExternalIDPView, error) {
|
||||||
return view.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(v.Db, externalIDPTable, externalUserID, idpConfigID, resourceOwner)
|
return view.ExternalIDPByExternalUserIDAndIDPConfigIDAndResourceOwner(v.Db, externalIDPTable, externalUserID, idpConfigID, resourceOwner, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ExternalIDPsByIDPConfigID(idpConfigID string) ([]*model.ExternalIDPView, error) {
|
func (v *View) ExternalIDPsByIDPConfigID(idpConfigID, instanceID string) ([]*model.ExternalIDPView, error) {
|
||||||
return view.ExternalIDPsByIDPConfigID(v.Db, externalIDPTable, idpConfigID)
|
return view.ExternalIDPsByIDPConfigID(v.Db, externalIDPTable, idpConfigID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, event *models.Event) error {
|
func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, event *models.Event) error {
|
||||||
@@ -40,24 +40,28 @@ func (v *View) PutExternalIDPs(event *models.Event, externalIDPs ...*model.Exter
|
|||||||
return v.ProcessedExternalIDPSequence(event)
|
return v.ProcessedExternalIDPSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, event *models.Event) error {
|
func (v *View) DeleteExternalIDP(externalUserID, idpConfigID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
|
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedExternalIDPSequence(event)
|
return v.ProcessedExternalIDPSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteExternalIDPsByUserID(userID string, event *models.Event) error {
|
func (v *View) DeleteExternalIDPsByUserID(userID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
|
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID, instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedExternalIDPSequence(event)
|
return v.ProcessedExternalIDPSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
|
func (v *View) GetLatestExternalIDPSequence(instanceID string) (*global_view.CurrentSequence, error) {
|
||||||
return v.latestSequence(externalIDPTable)
|
return v.latestSequence(externalIDPTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestExternalIDPSequences() ([]*global_view.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(externalIDPTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedExternalIDPSequence(event *models.Event) error {
|
func (v *View) ProcessedExternalIDPSequence(event *models.Event) error {
|
||||||
@@ -68,8 +72,8 @@ func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(externalIDPTable)
|
return v.updateSpoolerRunSequence(externalIDPTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestExternalIDPFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
func (v *View) GetLatestExternalIDPFailedEvent(sequence uint64, instanceID string) (*global_view.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(externalIDPTable, sequence)
|
return v.latestFailedEvent(externalIDPTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedExternalIDPFailedEvent(failedEvent *global_view.FailedEvent) error {
|
func (v *View) ProcessedExternalIDPFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||||
|
@@ -13,12 +13,12 @@ const (
|
|||||||
idpConfigTable = "auth.idp_configs"
|
idpConfigTable = "auth.idp_configs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) IDPConfigByID(idpID string) (*iam_es_model.IDPConfigView, error) {
|
func (v *View) IDPConfigByID(idpID, instanceID string) (*iam_es_model.IDPConfigView, error) {
|
||||||
return view.IDPByID(v.Db, idpConfigTable, idpID)
|
return view.IDPByID(v.Db, idpConfigTable, idpID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetIDPConfigsByAggregateID(aggregateID string) ([]*iam_es_model.IDPConfigView, error) {
|
func (v *View) GetIDPConfigsByAggregateID(aggregateID, instanceID string) ([]*iam_es_model.IDPConfigView, error) {
|
||||||
return view.GetIDPConfigsByAggregateID(v.Db, idpConfigTable, aggregateID)
|
return view.GetIDPConfigsByAggregateID(v.Db, idpConfigTable, aggregateID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*iam_es_model.IDPConfigView, uint64, error) {
|
func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*iam_es_model.IDPConfigView, uint64, error) {
|
||||||
@@ -34,15 +34,19 @@ func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, event *models.Event
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteIDPConfig(idpID string, event *models.Event) error {
|
func (v *View) DeleteIDPConfig(idpID string, event *models.Event) error {
|
||||||
err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
|
err := view.DeleteIDP(v.Db, idpConfigTable, idpID, event.InstanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedIDPConfigSequence(event)
|
return v.ProcessedIDPConfigSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
|
func (v *View) GetLatestIDPConfigSequence(instanceID string) (*global_view.CurrentSequence, error) {
|
||||||
return v.latestSequence(idpConfigTable)
|
return v.latestSequence(idpConfigTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestIDPConfigSequences() ([]*global_view.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(idpConfigTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedIDPConfigSequence(event *models.Event) error {
|
func (v *View) ProcessedIDPConfigSequence(event *models.Event) error {
|
||||||
@@ -53,8 +57,8 @@ func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(idpConfigTable)
|
return v.updateSpoolerRunSequence(idpConfigTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestIDPConfigFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
func (v *View) GetLatestIDPConfigFailedEvent(sequence uint64, instanceID string) (*global_view.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(idpConfigTable, sequence)
|
return v.latestFailedEvent(idpConfigTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedIDPConfigFailedEvent(failedEvent *global_view.FailedEvent) error {
|
func (v *View) ProcessedIDPConfigFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||||
|
@@ -13,16 +13,16 @@ const (
|
|||||||
idpProviderTable = "auth.idp_providers"
|
idpProviderTable = "auth.idp_providers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) IDPProviderByAggregateAndIDPConfigID(aggregateID, idpConfigID string) (*model.IDPProviderView, error) {
|
func (v *View) IDPProviderByAggregateAndIDPConfigID(aggregateID, idpConfigID, instanceID string) (*model.IDPProviderView, error) {
|
||||||
return view.GetIDPProviderByAggregateIDAndConfigID(v.Db, idpProviderTable, aggregateID, idpConfigID)
|
return view.GetIDPProviderByAggregateIDAndConfigID(v.Db, idpProviderTable, aggregateID, idpConfigID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) IDPProvidersByIDPConfigID(idpConfigID string) ([]*model.IDPProviderView, error) {
|
func (v *View) IDPProvidersByIDPConfigID(idpConfigID, instanceID string) ([]*model.IDPProviderView, error) {
|
||||||
return view.IDPProvidersByIdpConfigID(v.Db, idpProviderTable, idpConfigID)
|
return view.IDPProvidersByIdpConfigID(v.Db, idpProviderTable, idpConfigID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) IDPProvidersByAggregateIDAndState(aggregateID string, idpConfigState iam_model.IDPConfigState) ([]*model.IDPProviderView, error) {
|
func (v *View) IDPProvidersByAggregateIDAndState(aggregateID, instanceID string, idpConfigState iam_model.IDPConfigState) ([]*model.IDPProviderView, error) {
|
||||||
return view.IDPProvidersByAggregateIDAndState(v.Db, idpProviderTable, aggregateID, idpConfigState)
|
return view.IDPProvidersByAggregateIDAndState(v.Db, idpProviderTable, aggregateID, instanceID, idpConfigState)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) ([]*model.IDPProviderView, uint64, error) {
|
func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) ([]*model.IDPProviderView, uint64, error) {
|
||||||
@@ -45,24 +45,28 @@ func (v *View) PutIDPProviders(event *models.Event, providers ...*model.IDPProvi
|
|||||||
return v.ProcessedIDPProviderSequence(event)
|
return v.ProcessedIDPProviderSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, event *models.Event) error {
|
func (v *View) DeleteIDPProvider(aggregateID, idpConfigID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
|
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedIDPProviderSequence(event)
|
return v.ProcessedIDPProviderSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, event *models.Event) error {
|
func (v *View) DeleteIDPProvidersByAggregateID(aggregateID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteIDPProvidersByAggregateID(v.Db, idpProviderTable, aggregateID)
|
err := view.DeleteIDPProvidersByAggregateID(v.Db, idpProviderTable, aggregateID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedIDPProviderSequence(event)
|
return v.ProcessedIDPProviderSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
|
func (v *View) GetLatestIDPProviderSequence(instanceID string) (*global_view.CurrentSequence, error) {
|
||||||
return v.latestSequence(idpProviderTable)
|
return v.latestSequence(idpProviderTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestIDPProviderSequences() ([]*global_view.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(idpProviderTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedIDPProviderSequence(event *models.Event) error {
|
func (v *View) ProcessedIDPProviderSequence(event *models.Event) error {
|
||||||
@@ -73,8 +77,8 @@ func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(idpProviderTable)
|
return v.updateSpoolerRunSequence(idpProviderTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestIDPProviderFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
|
func (v *View) GetLatestIDPProviderFailedEvent(sequence uint64, instanceID string) (*global_view.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(idpProviderTable, sequence)
|
return v.latestFailedEvent(idpProviderTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedIDPProviderFailedEvent(failedEvent *global_view.FailedEvent) error {
|
func (v *View) ProcessedIDPProviderFailedEvent(failedEvent *global_view.FailedEvent) error {
|
||||||
|
@@ -12,8 +12,8 @@ const (
|
|||||||
orgPrgojectMappingTable = "auth.org_project_mapping"
|
orgPrgojectMappingTable = "auth.org_project_mapping"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) OrgProjectMappingByIDs(orgID, projectID string) (*model.OrgProjectMapping, error) {
|
func (v *View) OrgProjectMappingByIDs(orgID, projectID, instanceID string) (*model.OrgProjectMapping, error) {
|
||||||
return view.OrgProjectMappingByIDs(v.Db, orgPrgojectMappingTable, orgID, projectID)
|
return view.OrgProjectMappingByIDs(v.Db, orgPrgojectMappingTable, orgID, projectID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutOrgProjectMapping(mapping *model.OrgProjectMapping, event *models.Event) error {
|
func (v *View) PutOrgProjectMapping(mapping *model.OrgProjectMapping, event *models.Event) error {
|
||||||
@@ -24,24 +24,28 @@ func (v *View) PutOrgProjectMapping(mapping *model.OrgProjectMapping, event *mod
|
|||||||
return v.ProcessedOrgProjectMappingSequence(event)
|
return v.ProcessedOrgProjectMappingSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteOrgProjectMapping(orgID, projectID string, event *models.Event) error {
|
func (v *View) DeleteOrgProjectMapping(orgID, projectID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteOrgProjectMapping(v.Db, orgPrgojectMappingTable, orgID, projectID)
|
err := view.DeleteOrgProjectMapping(v.Db, orgPrgojectMappingTable, orgID, projectID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedOrgProjectMappingSequence(event)
|
return v.ProcessedOrgProjectMappingSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteOrgProjectMappingsByProjectID(projectID string) error {
|
func (v *View) DeleteOrgProjectMappingsByProjectID(projectID, instanceID string) error {
|
||||||
return view.DeleteOrgProjectMappingsByProjectID(v.Db, orgPrgojectMappingTable, projectID)
|
return view.DeleteOrgProjectMappingsByProjectID(v.Db, orgPrgojectMappingTable, projectID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteOrgProjectMappingsByProjectGrantID(projectGrantID string) error {
|
func (v *View) DeleteOrgProjectMappingsByProjectGrantID(projectGrantID, instanceID string) error {
|
||||||
return view.DeleteOrgProjectMappingsByProjectGrantID(v.Db, orgPrgojectMappingTable, projectGrantID)
|
return view.DeleteOrgProjectMappingsByProjectGrantID(v.Db, orgPrgojectMappingTable, projectGrantID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestOrgProjectMappingSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestOrgProjectMappingSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(orgPrgojectMappingTable)
|
return v.latestSequence(orgPrgojectMappingTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestOrgProjectMappingSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(orgPrgojectMappingTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedOrgProjectMappingSequence(event *models.Event) error {
|
func (v *View) ProcessedOrgProjectMappingSequence(event *models.Event) error {
|
||||||
@@ -52,8 +56,8 @@ func (v *View) UpdateOrgProjectMappingSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(orgPrgojectMappingTable)
|
return v.updateSpoolerRunSequence(orgPrgojectMappingTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestOrgProjectMappingFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestOrgProjectMappingFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(orgPrgojectMappingTable, sequence)
|
return v.latestFailedEvent(orgPrgojectMappingTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedOrgProjectMappingFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedOrgProjectMappingFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -13,12 +13,12 @@ const (
|
|||||||
refreshTokenTable = "auth.refresh_tokens"
|
refreshTokenTable = "auth.refresh_tokens"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) RefreshTokenByID(tokenID string) (*model.RefreshTokenView, error) {
|
func (v *View) RefreshTokenByID(tokenID, instanceID string) (*model.RefreshTokenView, error) {
|
||||||
return usr_view.RefreshTokenByID(v.Db, refreshTokenTable, tokenID)
|
return usr_view.RefreshTokenByID(v.Db, refreshTokenTable, tokenID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) RefreshTokensByUserID(userID string) ([]*model.RefreshTokenView, error) {
|
func (v *View) RefreshTokensByUserID(userID, instanceID string) ([]*model.RefreshTokenView, error) {
|
||||||
return usr_view.RefreshTokensByUserID(v.Db, refreshTokenTable, userID)
|
return usr_view.RefreshTokensByUserID(v.Db, refreshTokenTable, userID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) SearchRefreshTokens(request *user_model.RefreshTokenSearchRequest) ([]*model.RefreshTokenView, uint64, error) {
|
func (v *View) SearchRefreshTokens(request *user_model.RefreshTokenSearchRequest) ([]*model.RefreshTokenView, uint64, error) {
|
||||||
@@ -41,16 +41,16 @@ func (v *View) PutRefreshTokens(token []*model.RefreshTokenView, event *models.E
|
|||||||
return v.ProcessedRefreshTokenSequence(event)
|
return v.ProcessedRefreshTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteRefreshToken(tokenID string, event *models.Event) error {
|
func (v *View) DeleteRefreshToken(tokenID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteRefreshToken(v.Db, refreshTokenTable, tokenID)
|
err := usr_view.DeleteRefreshToken(v.Db, refreshTokenTable, tokenID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedRefreshTokenSequence(event)
|
return v.ProcessedRefreshTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUserRefreshTokens(userID string, event *models.Event) error {
|
func (v *View) DeleteUserRefreshTokens(userID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteUserRefreshTokens(v.Db, refreshTokenTable, userID)
|
err := usr_view.DeleteUserRefreshTokens(v.Db, refreshTokenTable, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -58,15 +58,19 @@ func (v *View) DeleteUserRefreshTokens(userID string, event *models.Event) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteApplicationRefreshTokens(event *models.Event, ids ...string) error {
|
func (v *View) DeleteApplicationRefreshTokens(event *models.Event, ids ...string) error {
|
||||||
err := usr_view.DeleteApplicationTokens(v.Db, refreshTokenTable, ids)
|
err := usr_view.DeleteApplicationTokens(v.Db, refreshTokenTable, event.InstanceID, ids)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedRefreshTokenSequence(event)
|
return v.ProcessedRefreshTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestRefreshTokenSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestRefreshTokenSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(refreshTokenTable)
|
return v.latestSequence(refreshTokenTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestRefreshTokenSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(refreshTokenTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedRefreshTokenSequence(event *models.Event) error {
|
func (v *View) ProcessedRefreshTokenSequence(event *models.Event) error {
|
||||||
@@ -77,8 +81,8 @@ func (v *View) UpdateRefreshTokenSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(refreshTokenTable)
|
return v.updateSpoolerRunSequence(refreshTokenTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestRefreshTokenFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestRefreshTokenFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(refreshTokenTable, sequence)
|
return v.latestFailedEvent(refreshTokenTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedRefreshTokenFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedRefreshTokenFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -12,21 +12,27 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
||||||
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.Sequence, event.CreationDate)
|
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.InstanceID, event.Sequence, event.CreationDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
|
func (v *View) latestSequence(viewName, instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return repository.LatestSequence(v.Db, sequencesTable, viewName)
|
return repository.LatestSequence(v.Db, sequencesTable, viewName, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) latestSequences(viewName string) ([]*repository.CurrentSequence, error) {
|
||||||
|
return repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
||||||
currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
|
currentSequences, err := repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if currentSequence.ViewName == "" {
|
for _, currentSequence := range currentSequences {
|
||||||
currentSequence.ViewName = viewName
|
if currentSequence.ViewName == "" {
|
||||||
|
currentSequence.ViewName = viewName
|
||||||
|
}
|
||||||
|
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
||||||
}
|
}
|
||||||
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
return repository.UpdateCurrentSequences(v.Db, sequencesTable, currentSequences)
|
||||||
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
|
|
||||||
}
|
}
|
||||||
|
@@ -12,12 +12,12 @@ const (
|
|||||||
tokenTable = "auth.tokens"
|
tokenTable = "auth.tokens"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) TokenByID(tokenID string) (*model.TokenView, error) {
|
func (v *View) TokenByID(tokenID, instanceID string) (*model.TokenView, error) {
|
||||||
return usr_view.TokenByID(v.Db, tokenTable, tokenID)
|
return usr_view.TokenByID(v.Db, tokenTable, tokenID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) TokensByUserID(userID string) ([]*model.TokenView, error) {
|
func (v *View) TokensByUserID(userID, instanceID string) ([]*model.TokenView, error) {
|
||||||
return usr_view.TokensByUserID(v.Db, tokenTable, userID)
|
return usr_view.TokensByUserID(v.Db, tokenTable, userID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutToken(token *model.TokenView, event *models.Event) error {
|
func (v *View) PutToken(token *model.TokenView, event *models.Event) error {
|
||||||
@@ -36,24 +36,24 @@ func (v *View) PutTokens(token []*model.TokenView, event *models.Event) error {
|
|||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteToken(tokenID string, event *models.Event) error {
|
func (v *View) DeleteToken(tokenID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID)
|
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteSessionTokens(agentID, userID string, event *models.Event) error {
|
func (v *View) DeleteSessionTokens(agentID, userID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID)
|
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUserTokens(userID string, event *models.Event) error {
|
func (v *View) DeleteUserTokens(userID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteUserTokens(v.Db, tokenTable, userID)
|
err := usr_view.DeleteUserTokens(v.Db, tokenTable, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -61,23 +61,27 @@ func (v *View) DeleteUserTokens(userID string, event *models.Event) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteApplicationTokens(event *models.Event, ids ...string) error {
|
func (v *View) DeleteApplicationTokens(event *models.Event, ids ...string) error {
|
||||||
err := usr_view.DeleteApplicationTokens(v.Db, tokenTable, ids)
|
err := usr_view.DeleteApplicationTokens(v.Db, tokenTable, event.InstanceID, ids)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteTokensFromRefreshToken(refreshTokenID string, event *models.Event) error {
|
func (v *View) DeleteTokensFromRefreshToken(refreshTokenID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteTokensFromRefreshToken(v.Db, tokenTable, refreshTokenID)
|
err := usr_view.DeleteTokensFromRefreshToken(v.Db, tokenTable, refreshTokenID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestTokenSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestTokenSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(tokenTable)
|
return v.latestSequence(tokenTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestTokenSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(tokenTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedTokenSequence(event *models.Event) error {
|
func (v *View) ProcessedTokenSequence(event *models.Event) error {
|
||||||
@@ -88,8 +92,8 @@ func (v *View) UpdateTokenSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(tokenTable)
|
return v.updateSpoolerRunSequence(tokenTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestTokenFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestTokenFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(tokenTable, sequence)
|
return v.latestFailedEvent(tokenTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedTokenFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedTokenFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -13,40 +13,40 @@ const (
|
|||||||
userTable = "auth.users"
|
userTable = "auth.users"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) UserByID(userID string) (*model.UserView, error) {
|
func (v *View) UserByID(userID, instanceID string) (*model.UserView, error) {
|
||||||
return view.UserByID(v.Db, userTable, userID)
|
return view.UserByID(v.Db, userTable, userID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserByUsername(userName string) (*model.UserView, error) {
|
func (v *View) UserByUsername(userName, instanceID string) (*model.UserView, error) {
|
||||||
return view.UserByUserName(v.Db, userTable, userName)
|
return view.UserByUserName(v.Db, userTable, userName, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserByLoginName(loginName string) (*model.UserView, error) {
|
func (v *View) UserByLoginName(loginName, instanceID string) (*model.UserView, error) {
|
||||||
return view.UserByLoginName(v.Db, userTable, loginName)
|
return view.UserByLoginName(v.Db, userTable, loginName, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserByLoginNameAndResourceOwner(loginName, resourceOwner string) (*model.UserView, error) {
|
func (v *View) UserByLoginNameAndResourceOwner(loginName, resourceOwner, instanceID string) (*model.UserView, error) {
|
||||||
return view.UserByLoginNameAndResourceOwner(v.Db, userTable, loginName, resourceOwner)
|
return view.UserByLoginNameAndResourceOwner(v.Db, userTable, loginName, resourceOwner, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UsersByOrgID(orgID string) ([]*model.UserView, error) {
|
func (v *View) UsersByOrgID(orgID, instanceID string) ([]*model.UserView, error) {
|
||||||
return view.UsersByOrgID(v.Db, userTable, orgID)
|
return view.UsersByOrgID(v.Db, userTable, orgID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserIDsByDomain(domain string) ([]string, error) {
|
func (v *View) UserIDsByDomain(domain, instanceID string) ([]string, error) {
|
||||||
return view.UserIDsByDomain(v.Db, userTable, domain)
|
return view.UserIDsByDomain(v.Db, userTable, domain, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserView, uint64, error) {
|
func (v *View) SearchUsers(request *usr_model.UserSearchRequest) ([]*model.UserView, uint64, error) {
|
||||||
return view.SearchUsers(v.Db, userTable, request)
|
return view.SearchUsers(v.Db, userTable, request)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetGlobalUserByLoginName(email string) (*model.UserView, error) {
|
func (v *View) GetGlobalUserByLoginName(email, instanceID string) (*model.UserView, error) {
|
||||||
return view.GetGlobalUserByLoginName(v.Db, userTable, email)
|
return view.GetGlobalUserByLoginName(v.Db, userTable, email, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
|
func (v *View) UserMFAs(userID, instanceID string) ([]*usr_model.MultiFactor, error) {
|
||||||
return view.UserMFAs(v.Db, userTable, userID)
|
return view.UserMFAs(v.Db, userTable, userID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutUser(user *model.UserView, event *models.Event) error {
|
func (v *View) PutUser(user *model.UserView, event *models.Event) error {
|
||||||
@@ -65,16 +65,20 @@ func (v *View) PutUsers(users []*model.UserView, event *models.Event) error {
|
|||||||
return v.ProcessedUserSequence(event)
|
return v.ProcessedUserSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUser(userID string, event *models.Event) error {
|
func (v *View) DeleteUser(userID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteUser(v.Db, userTable, userID)
|
err := view.DeleteUser(v.Db, userTable, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedUserSequence(event)
|
return v.ProcessedUserSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestUserSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(userTable)
|
return v.latestSequence(userTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestUserSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(userTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedUserSequence(event *models.Event) error {
|
func (v *View) ProcessedUserSequence(event *models.Event) error {
|
||||||
@@ -85,8 +89,8 @@ func (v *View) UpdateUserSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(userTable)
|
return v.updateSpoolerRunSequence(userTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestUserFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(userTable, sequence)
|
return v.latestFailedEvent(userTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedUserFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedUserFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -12,16 +12,16 @@ const (
|
|||||||
userSessionTable = "auth.user_sessions"
|
userSessionTable = "auth.user_sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) UserSessionByIDs(agentID, userID string) (*model.UserSessionView, error) {
|
func (v *View) UserSessionByIDs(agentID, userID, instanceID string) (*model.UserSessionView, error) {
|
||||||
return view.UserSessionByIDs(v.Db, userSessionTable, agentID, userID)
|
return view.UserSessionByIDs(v.Db, userSessionTable, agentID, userID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserSessionsByUserID(userID string) ([]*model.UserSessionView, error) {
|
func (v *View) UserSessionsByUserID(userID, instanceID string) ([]*model.UserSessionView, error) {
|
||||||
return view.UserSessionsByUserID(v.Db, userSessionTable, userID)
|
return view.UserSessionsByUserID(v.Db, userSessionTable, userID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserSessionsByAgentID(agentID string) ([]*model.UserSessionView, error) {
|
func (v *View) UserSessionsByAgentID(agentID, instanceID string) ([]*model.UserSessionView, error) {
|
||||||
return view.UserSessionsByAgentID(v.Db, userSessionTable, agentID)
|
return view.UserSessionsByAgentID(v.Db, userSessionTable, agentID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ActiveUserSessionsCount() (uint64, error) {
|
func (v *View) ActiveUserSessionsCount() (uint64, error) {
|
||||||
@@ -44,16 +44,20 @@ func (v *View) PutUserSessions(userSession []*model.UserSessionView, event *mode
|
|||||||
return v.ProcessedUserSessionSequence(event)
|
return v.ProcessedUserSessionSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUserSessions(userID string, event *models.Event) error {
|
func (v *View) DeleteUserSessions(userID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteUserSessions(v.Db, userSessionTable, userID)
|
err := view.DeleteUserSessions(v.Db, userSessionTable, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedUserSessionSequence(event)
|
return v.ProcessedUserSessionSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestUserSessionSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestUserSessionSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(userSessionTable)
|
return v.latestSequence(userSessionTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestUserSessionSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(userSessionTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedUserSessionSequence(event *models.Event) error {
|
func (v *View) ProcessedUserSessionSequence(event *models.Event) error {
|
||||||
@@ -64,8 +68,8 @@ func (v *View) UpdateUserSessionSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(userSessionTable)
|
return v.updateSpoolerRunSequence(userSessionTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestUserSessionFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestUserSessionFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(userSessionTable, sequence)
|
return v.latestFailedEvent(userSessionTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedUserSessionFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedUserSessionFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
|
"github.com/caos/zitadel/internal/authz/repository/eventsourcing/view"
|
||||||
"github.com/caos/zitadel/internal/crypto"
|
"github.com/caos/zitadel/internal/crypto"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
@@ -30,7 +31,7 @@ type TokenVerifierRepo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *TokenVerifierRepo) tokenByID(ctx context.Context, tokenID, userID string) (*usr_model.TokenView, error) {
|
func (repo *TokenVerifierRepo) tokenByID(ctx context.Context, tokenID, userID string) (*usr_model.TokenView, error) {
|
||||||
token, viewErr := repo.View.TokenByID(tokenID)
|
token, viewErr := repo.View.TokenByID(tokenID, authz.GetInstance(ctx).InstanceID())
|
||||||
if viewErr != nil && !caos_errs.IsNotFound(viewErr) {
|
if viewErr != nil && !caos_errs.IsNotFound(viewErr) {
|
||||||
return nil, viewErr
|
return nil, viewErr
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,7 @@ func (repo *TokenVerifierRepo) tokenByID(ctx context.Context, tokenID, userID st
|
|||||||
token.UserID = userID
|
token.UserID = userID
|
||||||
}
|
}
|
||||||
|
|
||||||
events, esErr := repo.getUserEvents(ctx, userID, token.Sequence)
|
events, esErr := repo.getUserEvents(ctx, userID, token.InstanceID, token.Sequence)
|
||||||
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
|
if caos_errs.IsNotFound(viewErr) && len(events) == 0 {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "EVENT-4T90g", "Errors.Token.NotFound")
|
return nil, caos_errs.ThrowNotFound(nil, "EVENT-4T90g", "Errors.Token.NotFound")
|
||||||
}
|
}
|
||||||
@@ -251,8 +252,8 @@ func (repo *TokenVerifierRepo) VerifierClientID(ctx context.Context, appName str
|
|||||||
return clientID, app.ProjectID, nil
|
return clientID, app.ProjectID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *TokenVerifierRepo) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) {
|
func (r *TokenVerifierRepo) getUserEvents(ctx context.Context, userID, instanceID string, sequence uint64) ([]*models.Event, error) {
|
||||||
query, err := usr_view.UserByIDQuery(userID, sequence)
|
query, err := usr_view.UserByIDQuery(userID, instanceID, sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -68,8 +68,8 @@ func (_ *UserMembership) AggregateTypes() []es_models.AggregateType {
|
|||||||
return []es_models.AggregateType{instance.AggregateType, org.AggregateType, project.AggregateType, user.AggregateType}
|
return []es_models.AggregateType{instance.AggregateType, org.AggregateType, project.AggregateType, user.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMembership) CurrentSequence() (uint64, error) {
|
func (m *UserMembership) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := m.view.GetLatestUserMembershipSequence()
|
sequence, err := m.view.GetLatestUserMembershipSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -77,13 +77,29 @@ func (m *UserMembership) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMembership) EventQuery() (*es_models.SearchQuery, error) {
|
func (m *UserMembership) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
sequence, err := m.view.GetLatestUserMembershipSequence()
|
sequences, err := m.view.GetLatestUserMembershipSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return es_models.NewSearchQuery().
|
query := es_models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(m.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
AggregateTypeFilter(m.AggregateTypes()...).
|
AggregateTypeFilter(m.AggregateTypes()...).
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMembership) Reduce(event *es_models.Event) (err error) {
|
func (m *UserMembership) Reduce(event *es_models.Event) (err error) {
|
||||||
@@ -110,14 +126,14 @@ func (m *UserMembership) processIAM(event *es_models.Event) (err error) {
|
|||||||
case instance.MemberAddedEventType:
|
case instance.MemberAddedEventType:
|
||||||
m.fillIamDisplayName(member)
|
m.fillIamDisplayName(member)
|
||||||
case instance.MemberChangedEventType:
|
case instance.MemberChangedEventType:
|
||||||
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam)
|
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, event.InstanceID, usr_model.MemberTypeIam)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = member.AppendEvent(event)
|
err = member.AppendEvent(event)
|
||||||
case instance.MemberRemovedEventType,
|
case instance.MemberRemovedEventType,
|
||||||
instance.MemberCascadeRemovedEventType:
|
instance.MemberCascadeRemovedEventType:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, event.InstanceID, usr_model.MemberTypeIam, event)
|
||||||
default:
|
default:
|
||||||
return m.view.ProcessedUserMembershipSequence(event)
|
return m.view.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
@@ -142,14 +158,14 @@ func (m *UserMembership) processOrg(event *es_models.Event) (err error) {
|
|||||||
case org.MemberAddedEventType:
|
case org.MemberAddedEventType:
|
||||||
err = m.fillOrgName(member)
|
err = m.fillOrgName(member)
|
||||||
case org.MemberChangedEventType:
|
case org.MemberChangedEventType:
|
||||||
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation)
|
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, event.InstanceID, usr_model.MemberTypeOrganisation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = member.AppendEvent(event)
|
err = member.AppendEvent(event)
|
||||||
case org.MemberRemovedEventType,
|
case org.MemberRemovedEventType,
|
||||||
org.MemberCascadeRemovedEventType:
|
org.MemberCascadeRemovedEventType:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, event.InstanceID, usr_model.MemberTypeOrganisation, event)
|
||||||
case org.OrgChangedEventType:
|
case org.OrgChangedEventType:
|
||||||
return m.updateOrgName(event)
|
return m.updateOrgName(event)
|
||||||
default:
|
default:
|
||||||
@@ -179,7 +195,7 @@ func (m *UserMembership) updateOrgName(event *es_models.Event) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
memberships, err := m.view.UserMembershipsByResourceOwner(event.ResourceOwner)
|
memberships, err := m.view.UserMembershipsByResourceOwner(event.ResourceOwner, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -206,28 +222,28 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
err = m.fillOrgName(member)
|
err = m.fillOrgName(member)
|
||||||
case project.MemberChangedType:
|
case project.MemberChangedType:
|
||||||
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject)
|
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, event.AggregateID, event.InstanceID, usr_model.MemberTypeProject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = member.AppendEvent(event)
|
err = member.AppendEvent(event)
|
||||||
case project.MemberRemovedType, project.MemberCascadeRemovedType:
|
case project.MemberRemovedType, project.MemberCascadeRemovedType:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, event.InstanceID, usr_model.MemberTypeProject, event)
|
||||||
case project.GrantMemberChangedType:
|
case project.GrantMemberChangedType:
|
||||||
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
|
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, event.InstanceID, usr_model.MemberTypeProjectGrant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = member.AppendEvent(event)
|
err = member.AppendEvent(event)
|
||||||
case project.GrantMemberRemovedType,
|
case project.GrantMemberRemovedType,
|
||||||
project.GrantMemberCascadeRemovedType:
|
project.GrantMemberCascadeRemovedType:
|
||||||
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event)
|
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, member.InstanceID, usr_model.MemberTypeProjectGrant, event)
|
||||||
case project.ProjectChangedType:
|
case project.ProjectChangedType:
|
||||||
return m.updateProjectDisplayName(event)
|
return m.updateProjectDisplayName(event)
|
||||||
case project.ProjectRemovedType:
|
case project.ProjectRemovedType:
|
||||||
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event)
|
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.InstanceID, event)
|
||||||
case project.GrantRemovedType:
|
case project.GrantRemovedType:
|
||||||
return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event)
|
return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, member.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return m.view.ProcessedUserMembershipSequence(event)
|
return m.view.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
@@ -238,7 +254,7 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
|
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
|
||||||
project, err := m.getProjectByID(context.Background(), member.AggregateID)
|
project, err := m.getProjectByID(context.Background(), member.AggregateID, member.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -256,7 +272,7 @@ func (m *UserMembership) updateProjectDisplayName(event *es_models.Event) error
|
|||||||
return m.view.ProcessedUserMembershipSequence(event)
|
return m.view.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
memberships, err := m.view.UserMembershipsByAggregateID(event.AggregateID)
|
memberships, err := m.view.UserMembershipsByAggregateID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -269,7 +285,7 @@ func (m *UserMembership) updateProjectDisplayName(event *es_models.Event) error
|
|||||||
func (m *UserMembership) processUser(event *es_models.Event) (err error) {
|
func (m *UserMembership) processUser(event *es_models.Event) (err error) {
|
||||||
switch eventstore.EventType(event.Type) {
|
switch eventstore.EventType(event.Type) {
|
||||||
case user.UserRemovedType:
|
case user.UserRemovedType:
|
||||||
return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event)
|
return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return m.view.ProcessedUserMembershipSequence(event)
|
return m.view.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
@@ -306,8 +322,8 @@ func (u *UserMembership) getOrgByID(ctx context.Context, orgID string) (*org_mod
|
|||||||
return org_es_model.OrgToModel(esOrg), nil
|
return org_es_model.OrgToModel(esOrg), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserMembership) getProjectByID(ctx context.Context, projID string) (*proj_model.Project, error) {
|
func (u *UserMembership) getProjectByID(ctx context.Context, projID, instanceID string) (*proj_model.Project, error) {
|
||||||
query, err := proj_view.ProjectByIDQuery(projID, 0)
|
query, err := proj_view.ProjectByIDQuery(projID, instanceID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,9 @@ package spooler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
es_locker "github.com/caos/zitadel/internal/eventstore/v1/locker"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
es_locker "github.com/caos/zitadel/internal/eventstore/v1/locker"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -14,6 +15,6 @@ type locker struct {
|
|||||||
dbClient *sql.DB
|
dbClient *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
|
func (l *locker) Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error {
|
||||||
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime)
|
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, instanceID, waitTime)
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,6 @@ func (v *View) saveFailedEvent(failedEvent *repository.FailedEvent) error {
|
|||||||
return repository.SaveFailedEvent(v.Db, errTable, failedEvent)
|
return repository.SaveFailedEvent(v.Db, errTable, failedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestFailedEvent(viewName string, sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) latestFailedEvent(viewName, instanceID string, sequence uint64) (*repository.FailedEvent, error) {
|
||||||
return repository.LatestFailedEvent(v.Db, errTable, viewName, sequence)
|
return repository.LatestFailedEvent(v.Db, errTable, viewName, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
@@ -12,21 +12,27 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
||||||
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.Sequence, event.CreationDate)
|
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.InstanceID, event.Sequence, event.CreationDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
|
func (v *View) latestSequence(viewName, instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return repository.LatestSequence(v.Db, sequencesTable, viewName)
|
return repository.LatestSequence(v.Db, sequencesTable, viewName, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) latestSequences(viewName string) ([]*repository.CurrentSequence, error) {
|
||||||
|
return repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
||||||
currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
|
currentSequences, err := repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if currentSequence.ViewName == "" {
|
for _, currentSequence := range currentSequences {
|
||||||
currentSequence.ViewName = viewName
|
if currentSequence.ViewName == "" {
|
||||||
|
currentSequence.ViewName = viewName
|
||||||
|
}
|
||||||
|
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
||||||
}
|
}
|
||||||
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
return repository.UpdateCurrentSequences(v.Db, sequencesTable, currentSequences)
|
||||||
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
|
|
||||||
}
|
}
|
||||||
|
@@ -12,8 +12,8 @@ const (
|
|||||||
tokenTable = "auth.tokens"
|
tokenTable = "auth.tokens"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) TokenByID(tokenID string) (*usr_view_model.TokenView, error) {
|
func (v *View) TokenByID(tokenID, instanceID string) (*usr_view_model.TokenView, error) {
|
||||||
return usr_view.TokenByID(v.Db, tokenTable, tokenID)
|
return usr_view.TokenByID(v.Db, tokenTable, tokenID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutToken(token *usr_view_model.TokenView, event *models.Event) error {
|
func (v *View) PutToken(token *usr_view_model.TokenView, event *models.Event) error {
|
||||||
@@ -24,24 +24,24 @@ func (v *View) PutToken(token *usr_view_model.TokenView, event *models.Event) er
|
|||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteToken(tokenID string, event *models.Event) error {
|
func (v *View) DeleteToken(tokenID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID)
|
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteSessionTokens(agentID, userID string, event *models.Event) error {
|
func (v *View) DeleteSessionTokens(agentID, userID, instanceID string, event *models.Event) error {
|
||||||
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID)
|
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedTokenSequence(event)
|
return v.ProcessedTokenSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestTokenSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestTokenSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(tokenTable)
|
return v.latestSequence(tokenTable, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedTokenSequence(event *models.Event) error {
|
func (v *View) ProcessedTokenSequence(event *models.Event) error {
|
||||||
@@ -52,8 +52,8 @@ func (v *View) UpdateTokenSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(tokenTable)
|
return v.updateSpoolerRunSequence(tokenTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestTokenFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestTokenFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(tokenTable, sequence)
|
return v.latestFailedEvent(tokenTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedTokenFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedTokenFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -13,16 +13,16 @@ const (
|
|||||||
userMembershipTable = "authz.user_memberships"
|
userMembershipTable = "authz.user_memberships"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) UserMembershipByIDs(userID, aggregateID, objectID string, memberType usr_model.MemberType) (*model.UserMembershipView, error) {
|
func (v *View) UserMembershipByIDs(userID, aggregateID, objectID, instanceID string, memberType usr_model.MemberType) (*model.UserMembershipView, error) {
|
||||||
return view.UserMembershipByIDs(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
|
return view.UserMembershipByIDs(v.Db, userMembershipTable, userID, aggregateID, objectID, instanceID, memberType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserMembershipsByAggregateID(aggregateID string) ([]*model.UserMembershipView, error) {
|
func (v *View) UserMembershipsByAggregateID(aggregateID, instanceID string) ([]*model.UserMembershipView, error) {
|
||||||
return view.UserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
|
return view.UserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) UserMembershipsByResourceOwner(resourceOwner string) ([]*model.UserMembershipView, error) {
|
func (v *View) UserMembershipsByResourceOwner(resourceOwner, instanceID string) ([]*model.UserMembershipView, error) {
|
||||||
return view.UserMembershipsByResourceOwner(v.Db, userMembershipTable, resourceOwner)
|
return view.UserMembershipsByResourceOwner(v.Db, userMembershipTable, resourceOwner, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequest) ([]*model.UserMembershipView, uint64, error) {
|
func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequest) ([]*model.UserMembershipView, uint64, error) {
|
||||||
@@ -45,40 +45,44 @@ func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, e
|
|||||||
return v.ProcessedUserMembershipSequence(event)
|
return v.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, event *models.Event) error {
|
func (v *View) DeleteUserMembership(userID, aggregateID, objectID, instanceID string, memberType usr_model.MemberType, event *models.Event) error {
|
||||||
err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
|
err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, instanceID, memberType)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedUserMembershipSequence(event)
|
return v.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUserMembershipsByUserID(userID string, event *models.Event) error {
|
func (v *View) DeleteUserMembershipsByUserID(userID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteUserMembershipsByUserID(v.Db, userMembershipTable, userID)
|
err := view.DeleteUserMembershipsByUserID(v.Db, userMembershipTable, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedUserMembershipSequence(event)
|
return v.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, event *models.Event) error {
|
func (v *View) DeleteUserMembershipsByAggregateID(aggregateID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteUserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
|
err := view.DeleteUserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedUserMembershipSequence(event)
|
return v.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, event *models.Event) error {
|
func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteUserMembershipsByAggregateIDAndObjectID(v.Db, userMembershipTable, aggregateID, objectID)
|
err := view.DeleteUserMembershipsByAggregateIDAndObjectID(v.Db, userMembershipTable, aggregateID, objectID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedUserMembershipSequence(event)
|
return v.ProcessedUserMembershipSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestUserMembershipSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestUserMembershipSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(userMembershipTable)
|
return v.latestSequence(userMembershipTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestUserMembershipSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(userMembershipTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedUserMembershipSequence(event *models.Event) error {
|
func (v *View) ProcessedUserMembershipSequence(event *models.Event) error {
|
||||||
@@ -89,8 +93,8 @@ func (v *View) UpdateUserMembershipSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(userMembershipTable)
|
return v.updateSpoolerRunSequence(userMembershipTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestUserMembershipFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestUserMembershipFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(userMembershipTable, sequence)
|
return v.latestFailedEvent(userMembershipTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedUserMembershipFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedUserMembershipFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/api/authz"
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
@@ -12,7 +14,6 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/caos/zitadel/internal/repository/instance"
|
"github.com/caos/zitadel/internal/repository/instance"
|
||||||
"github.com/caos/zitadel/internal/repository/policy"
|
"github.com/caos/zitadel/internal/repository/policy"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommandSide_AddDefaultPasswordAgePolicy(t *testing.T) {
|
func TestCommandSide_AddDefaultPasswordAgePolicy(t *testing.T) {
|
||||||
|
@@ -10,11 +10,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
currentSequenceStmtFormat = `SELECT current_sequence, aggregate_type FROM %s WHERE projection_name = $1 FOR UPDATE`
|
currentSequenceStmtFormat = `SELECT current_sequence, aggregate_type, instance_id FROM %s WHERE projection_name = $1 FOR UPDATE`
|
||||||
updateCurrentSequencesStmtFormat = `UPSERT INTO %s (projection_name, aggregate_type, current_sequence, timestamp) VALUES `
|
updateCurrentSequencesStmtFormat = `UPSERT INTO %s (projection_name, aggregate_type, current_sequence, instance_id, timestamp) VALUES `
|
||||||
)
|
)
|
||||||
|
|
||||||
type currentSequences map[eventstore.AggregateType]uint64
|
type currentSequences map[eventstore.AggregateType][]*instanceSequence
|
||||||
|
|
||||||
|
type instanceSequence struct {
|
||||||
|
instanceID string
|
||||||
|
sequence uint64
|
||||||
|
}
|
||||||
|
|
||||||
func (h *StatementHandler) currentSequences(query func(string, ...interface{}) (*sql.Rows, error)) (currentSequences, error) {
|
func (h *StatementHandler) currentSequences(query func(string, ...interface{}) (*sql.Rows, error)) (currentSequences, error) {
|
||||||
rows, err := query(h.currentSequenceStmt, h.ProjectionName)
|
rows, err := query(h.currentSequenceStmt, h.ProjectionName)
|
||||||
@@ -29,14 +34,18 @@ func (h *StatementHandler) currentSequences(query func(string, ...interface{}) (
|
|||||||
var (
|
var (
|
||||||
aggregateType eventstore.AggregateType
|
aggregateType eventstore.AggregateType
|
||||||
sequence uint64
|
sequence uint64
|
||||||
|
instanceID string
|
||||||
)
|
)
|
||||||
|
|
||||||
err = rows.Scan(&sequence, &aggregateType)
|
err = rows.Scan(&sequence, &aggregateType, &instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.ThrowInternal(err, "CRDB-dbatK", "scan failed")
|
return nil, errors.ThrowInternal(err, "CRDB-dbatK", "scan failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
sequences[aggregateType] = sequence
|
sequences[aggregateType] = append(sequences[aggregateType], &instanceSequence{
|
||||||
|
sequence: sequence,
|
||||||
|
instanceID: instanceID,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err = rows.Close(); err != nil {
|
||||||
@@ -54,10 +63,12 @@ func (h *StatementHandler) updateCurrentSequences(tx *sql.Tx, sequences currentS
|
|||||||
valueQueries := make([]string, 0, len(sequences))
|
valueQueries := make([]string, 0, len(sequences))
|
||||||
valueCounter := 0
|
valueCounter := 0
|
||||||
values := make([]interface{}, 0, len(sequences)*3)
|
values := make([]interface{}, 0, len(sequences)*3)
|
||||||
for aggregate, sequence := range sequences {
|
for aggregate, instanceSequence := range sequences {
|
||||||
valueQueries = append(valueQueries, "($"+strconv.Itoa(valueCounter+1)+", $"+strconv.Itoa(valueCounter+2)+", $"+strconv.Itoa(valueCounter+3)+", NOW())")
|
for _, sequence := range instanceSequence {
|
||||||
valueCounter += 3
|
valueQueries = append(valueQueries, "($"+strconv.Itoa(valueCounter+1)+", $"+strconv.Itoa(valueCounter+2)+", $"+strconv.Itoa(valueCounter+3)+", $"+strconv.Itoa(valueCounter+4)+", NOW())")
|
||||||
values = append(values, h.ProjectionName, aggregate, sequence)
|
valueCounter += 4
|
||||||
|
values = append(values, h.ProjectionName, aggregate, sequence.sequence, sequence.instanceID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := tx.Exec(h.updateSequencesBaseStmt+strings.Join(valueQueries, ", "), values...)
|
res, err := tx.Exec(h.updateSequencesBaseStmt+strings.Join(valueQueries, ", "), values...)
|
||||||
|
@@ -3,7 +3,7 @@ package crdb
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"log"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -123,22 +123,22 @@ func expectSavePointRelease() func(sqlmock.Sqlmock) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectCurrentSequence(tableName, projection string, seq uint64, aggregateType string) func(sqlmock.Sqlmock) {
|
func expectCurrentSequence(tableName, projection string, seq uint64, aggregateType, instanceID string) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
projection,
|
||||||
).
|
).
|
||||||
WillReturnRows(
|
WillReturnRows(
|
||||||
sqlmock.NewRows([]string{"current_sequence", "aggregate_type"}).
|
sqlmock.NewRows([]string{"current_sequence", "aggregate_type", "instance_id"}).
|
||||||
AddRow(seq, aggregateType),
|
AddRow(seq, aggregateType, instanceID),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectCurrentSequenceErr(tableName, projection string, err error) func(sqlmock.Sqlmock) {
|
func expectCurrentSequenceErr(tableName, projection string, err error) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
projection,
|
||||||
).
|
).
|
||||||
@@ -148,37 +148,38 @@ func expectCurrentSequenceErr(tableName, projection string, err error) func(sqlm
|
|||||||
|
|
||||||
func expectCurrentSequenceNoRows(tableName, projection string) func(sqlmock.Sqlmock) {
|
func expectCurrentSequenceNoRows(tableName, projection string) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
projection,
|
||||||
).
|
).
|
||||||
WillReturnRows(
|
WillReturnRows(
|
||||||
sqlmock.NewRows([]string{"current_sequence", "aggregate_type"}),
|
sqlmock.NewRows([]string{"current_sequence", "aggregate_type", "instance_id"}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectCurrentSequenceScanErr(tableName, projection string) func(sqlmock.Sqlmock) {
|
func expectCurrentSequenceScanErr(tableName, projection string) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM ` + tableName + ` WHERE projection_name = \$1 FOR UPDATE`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
projection,
|
||||||
).
|
).
|
||||||
WillReturnRows(
|
WillReturnRows(
|
||||||
sqlmock.NewRows([]string{"current_sequence", "aggregate_type"}).
|
sqlmock.NewRows([]string{"current_sequence", "aggregate_type", "instance_id"}).
|
||||||
RowError(0, sql.ErrTxDone).
|
RowError(0, sql.ErrTxDone).
|
||||||
AddRow(0, "agg"),
|
AddRow(0, "agg", "instanceID"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectUpdateCurrentSequence(tableName, projection string, seq uint64, aggregateType string) func(sqlmock.Sqlmock) {
|
func expectUpdateCurrentSequence(tableName, projection string, seq uint64, aggregateType, instanceID string) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, timestamp\) VALUES \(\$1, \$2, \$3, NOW\(\)\)`).
|
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\)`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
projection,
|
||||||
aggregateType,
|
aggregateType,
|
||||||
seq,
|
seq,
|
||||||
|
instanceID,
|
||||||
).
|
).
|
||||||
WillReturnResult(
|
WillReturnResult(
|
||||||
sqlmock.NewResult(1, 1),
|
sqlmock.NewResult(1, 1),
|
||||||
@@ -187,16 +188,26 @@ func expectUpdateCurrentSequence(tableName, projection string, seq uint64, aggre
|
|||||||
}
|
}
|
||||||
|
|
||||||
func expectUpdateTwoCurrentSequence(tableName, projection string, sequences currentSequences) func(sqlmock.Sqlmock) {
|
func expectUpdateTwoCurrentSequence(tableName, projection string, sequences currentSequences) func(sqlmock.Sqlmock) {
|
||||||
|
//sort them so the args will always have the same order
|
||||||
|
keys := make([]string, 0, len(sequences))
|
||||||
|
for k := range sequences {
|
||||||
|
keys = append(keys, string(k))
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
args := make([]driver.Value, len(keys)*4)
|
||||||
|
for i, k := range keys {
|
||||||
|
aggregateType := eventstore.AggregateType(k)
|
||||||
|
for _, sequence := range sequences[aggregateType] {
|
||||||
|
args[i*4] = projection
|
||||||
|
args[i*4+1] = aggregateType
|
||||||
|
args[i*4+2] = sequence.sequence
|
||||||
|
args[i*4+3] = sequence.instanceID
|
||||||
|
}
|
||||||
|
}
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
matcher := ¤tSequenceMatcher{seq: sequences}
|
m.ExpectExec("UPSERT INTO " + tableName + ` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\), \(\$5, \$6, \$7, \$8, NOW\(\)\)`).
|
||||||
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, timestamp\) VALUES \(\$1, \$2, \$3, NOW\(\)\), \(\$4, \$5, \$6, NOW\(\)\)`).
|
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
args...,
|
||||||
matcher,
|
|
||||||
matcher,
|
|
||||||
projection,
|
|
||||||
matcher,
|
|
||||||
matcher,
|
|
||||||
).
|
).
|
||||||
WillReturnResult(
|
WillReturnResult(
|
||||||
sqlmock.NewResult(1, 1),
|
sqlmock.NewResult(1, 1),
|
||||||
@@ -204,51 +215,27 @@ func expectUpdateTwoCurrentSequence(tableName, projection string, sequences curr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type currentSequenceMatcher struct {
|
func expectUpdateCurrentSequenceErr(tableName, projection string, seq uint64, err error, aggregateType, instanceID string) func(sqlmock.Sqlmock) {
|
||||||
seq currentSequences
|
|
||||||
currentAggregate eventstore.AggregateType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *currentSequenceMatcher) Match(value driver.Value) bool {
|
|
||||||
switch v := value.(type) {
|
|
||||||
case string:
|
|
||||||
if m.currentAggregate != "" {
|
|
||||||
log.Printf("expected sequence of %s but got next aggregate type %s", m.currentAggregate, value)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
_, ok := m.seq[eventstore.AggregateType(v)]
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
m.currentAggregate = eventstore.AggregateType(v)
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
seq := m.seq[m.currentAggregate]
|
|
||||||
m.currentAggregate = ""
|
|
||||||
delete(m.seq, m.currentAggregate)
|
|
||||||
return int64(seq) == value.(int64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func expectUpdateCurrentSequenceErr(tableName, projection string, seq uint64, err error, aggregateType string) func(sqlmock.Sqlmock) {
|
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, timestamp\) VALUES \(\$1, \$2, \$3, NOW\(\)\)`).
|
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\)`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
projection,
|
||||||
aggregateType,
|
aggregateType,
|
||||||
seq,
|
seq,
|
||||||
|
instanceID,
|
||||||
).
|
).
|
||||||
WillReturnError(err)
|
WillReturnError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectUpdateCurrentSequenceNoRows(tableName, projection string, seq uint64, aggregateType string) func(sqlmock.Sqlmock) {
|
func expectUpdateCurrentSequenceNoRows(tableName, projection string, seq uint64, aggregateType, instanceID string) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, timestamp\) VALUES \(\$1, \$2, \$3, NOW\(\)\)`).
|
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\)`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
projection,
|
projection,
|
||||||
aggregateType,
|
aggregateType,
|
||||||
seq,
|
seq,
|
||||||
|
instanceID,
|
||||||
).
|
).
|
||||||
WillReturnResult(
|
WillReturnResult(
|
||||||
sqlmock.NewResult(0, 0),
|
sqlmock.NewResult(0, 0),
|
||||||
@@ -256,17 +243,18 @@ func expectUpdateCurrentSequenceNoRows(tableName, projection string, seq uint64,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectLock(lockTable, workerName string, d time.Duration) func(sqlmock.Sqlmock) {
|
func expectLock(lockTable, workerName string, d time.Duration, instanceID string) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectExec(`INSERT INTO `+lockTable+
|
m.ExpectExec(`INSERT INTO `+lockTable+
|
||||||
` \(locker_id, locked_until, projection_name\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\)`+
|
` \(locker_id, locked_until, projection_name, instance_id\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\, \$4\)`+
|
||||||
` ON CONFLICT \(projection_name\)`+
|
` ON CONFLICT \(projection_name, instance_id\)`+
|
||||||
` DO UPDATE SET locker_id = \$1, locked_until = now\(\)\+\$2::INTERVAL`+
|
` DO UPDATE SET locker_id = \$1, locked_until = now\(\)\+\$2::INTERVAL`+
|
||||||
` WHERE `+lockTable+`\.projection_name = \$3 AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
` WHERE `+lockTable+`\.projection_name = \$3 AND `+lockTable+`\.instance_id = \$4 AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
workerName,
|
workerName,
|
||||||
float64(d),
|
float64(d),
|
||||||
projectionName,
|
projectionName,
|
||||||
|
instanceID,
|
||||||
).
|
).
|
||||||
WillReturnResult(
|
WillReturnResult(
|
||||||
sqlmock.NewResult(1, 1),
|
sqlmock.NewResult(1, 1),
|
||||||
@@ -274,33 +262,35 @@ func expectLock(lockTable, workerName string, d time.Duration) func(sqlmock.Sqlm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectLockNoRows(lockTable, workerName string, d time.Duration) func(sqlmock.Sqlmock) {
|
func expectLockNoRows(lockTable, workerName string, d time.Duration, instanceID string) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectExec(`INSERT INTO `+lockTable+
|
m.ExpectExec(`INSERT INTO `+lockTable+
|
||||||
` \(locker_id, locked_until, projection_name\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\)`+
|
` \(locker_id, locked_until, projection_name, instance_id\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\, \$4\)`+
|
||||||
` ON CONFLICT \(projection_name\)`+
|
` ON CONFLICT \(projection_name, instance_id\)`+
|
||||||
` DO UPDATE SET locker_id = \$1, locked_until = now\(\)\+\$2::INTERVAL`+
|
` DO UPDATE SET locker_id = \$1, locked_until = now\(\)\+\$2::INTERVAL`+
|
||||||
` WHERE `+lockTable+`\.projection_name = \$3 AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
` WHERE `+lockTable+`\.projection_name = \$3 AND `+lockTable+`\.instance_id = \$4 AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
workerName,
|
workerName,
|
||||||
float64(d),
|
float64(d),
|
||||||
projectionName,
|
projectionName,
|
||||||
|
instanceID,
|
||||||
).
|
).
|
||||||
WillReturnResult(driver.ResultNoRows)
|
WillReturnResult(driver.ResultNoRows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectLockErr(lockTable, workerName string, d time.Duration, err error) func(sqlmock.Sqlmock) {
|
func expectLockErr(lockTable, workerName string, d time.Duration, instanceID string, err error) func(sqlmock.Sqlmock) {
|
||||||
return func(m sqlmock.Sqlmock) {
|
return func(m sqlmock.Sqlmock) {
|
||||||
m.ExpectExec(`INSERT INTO `+lockTable+
|
m.ExpectExec(`INSERT INTO `+lockTable+
|
||||||
` \(locker_id, locked_until, projection_name\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\)`+
|
` \(locker_id, locked_until, projection_name, instance_id\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\, \$4\)`+
|
||||||
` ON CONFLICT \(projection_name\)`+
|
` ON CONFLICT \(projection_name, instance_id\)`+
|
||||||
` DO UPDATE SET locker_id = \$1, locked_until = now\(\)\+\$2::INTERVAL`+
|
` DO UPDATE SET locker_id = \$1, locked_until = now\(\)\+\$2::INTERVAL`+
|
||||||
` WHERE `+lockTable+`\.projection_name = \$3 AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
` WHERE `+lockTable+`\.projection_name = \$3 AND `+lockTable+`\.instance_id = \$4 AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
workerName,
|
workerName,
|
||||||
float64(d),
|
float64(d),
|
||||||
projectionName,
|
projectionName,
|
||||||
|
instanceID,
|
||||||
).
|
).
|
||||||
WillReturnError(err)
|
WillReturnError(err)
|
||||||
}
|
}
|
||||||
|
@@ -101,15 +101,34 @@ func (h *StatementHandler) SearchQuery() (*eventstore.SearchQueryBuilder, uint64
|
|||||||
|
|
||||||
queryBuilder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).Limit(h.bulkLimit)
|
queryBuilder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).Limit(h.bulkLimit)
|
||||||
for _, aggregateType := range h.aggregates {
|
for _, aggregateType := range h.aggregates {
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences[aggregateType] {
|
||||||
|
instances = appendToIgnoredInstances(instances, sequence.instanceID)
|
||||||
|
queryBuilder.
|
||||||
|
AddQuery().
|
||||||
|
AggregateTypes(aggregateType).
|
||||||
|
SequenceGreater(sequence.sequence).
|
||||||
|
InstanceID(sequence.instanceID)
|
||||||
|
}
|
||||||
queryBuilder.
|
queryBuilder.
|
||||||
AddQuery().
|
AddQuery().
|
||||||
AggregateTypes(aggregateType).
|
AggregateTypes(aggregateType).
|
||||||
SequenceGreater(sequences[aggregateType])
|
SequenceGreater(0).
|
||||||
|
ExcludedInstanceID(instances...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return queryBuilder, h.bulkLimit, nil
|
return queryBuilder, h.bulkLimit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendToIgnoredInstances(instances []string, id string) []string {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if instance == id {
|
||||||
|
return instances
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(instances, id)
|
||||||
|
}
|
||||||
|
|
||||||
//Update implements handler.Update
|
//Update implements handler.Update
|
||||||
func (h *StatementHandler) Update(ctx context.Context, stmts []*handler.Statement, reduce handler.Reduce) (unexecutedStmts []*handler.Statement, err error) {
|
func (h *StatementHandler) Update(ctx context.Context, stmts []*handler.Statement, reduce handler.Reduce) (unexecutedStmts []*handler.Statement, err error) {
|
||||||
tx, err := h.client.BeginTx(ctx, nil)
|
tx, err := h.client.BeginTx(ctx, nil)
|
||||||
@@ -127,7 +146,7 @@ func (h *StatementHandler) Update(ctx context.Context, stmts []*handler.Statemen
|
|||||||
// because there could be events between current sequence and a creation event
|
// because there could be events between current sequence and a creation event
|
||||||
// and we cannot check via stmt.PreviousSequence
|
// and we cannot check via stmt.PreviousSequence
|
||||||
if stmts[0].PreviousSequence == 0 {
|
if stmts[0].PreviousSequence == 0 {
|
||||||
previousStmts, err := h.fetchPreviousStmts(ctx, stmts[0].Sequence, sequences, reduce)
|
previousStmts, err := h.fetchPreviousStmts(ctx, stmts[0].Sequence, stmts[0].InstanceID, sequences, reduce)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return stmts, err
|
return stmts, err
|
||||||
@@ -164,27 +183,25 @@ func (h *StatementHandler) Update(ctx context.Context, stmts []*handler.Statemen
|
|||||||
return unexecutedStmts, nil
|
return unexecutedStmts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StatementHandler) fetchPreviousStmts(
|
func (h *StatementHandler) fetchPreviousStmts(ctx context.Context, stmtSeq uint64, instanceID string, sequences currentSequences, reduce handler.Reduce) (previousStmts []*handler.Statement, err error) {
|
||||||
ctx context.Context,
|
|
||||||
stmtSeq uint64,
|
|
||||||
sequences currentSequences,
|
|
||||||
reduce handler.Reduce,
|
|
||||||
) (previousStmts []*handler.Statement, err error) {
|
|
||||||
|
|
||||||
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent)
|
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent)
|
||||||
queriesAdded := false
|
queriesAdded := false
|
||||||
for _, aggregateType := range h.aggregates {
|
for _, aggregateType := range h.aggregates {
|
||||||
if stmtSeq <= sequences[aggregateType] {
|
for _, sequence := range sequences[aggregateType] {
|
||||||
continue
|
if stmtSeq <= sequence.sequence && instanceID == sequence.instanceID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
query.
|
||||||
|
AddQuery().
|
||||||
|
AggregateTypes(aggregateType).
|
||||||
|
SequenceGreater(sequence.sequence).
|
||||||
|
SequenceLess(stmtSeq).
|
||||||
|
InstanceID(sequence.instanceID)
|
||||||
|
|
||||||
|
queriesAdded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
query.
|
|
||||||
AddQuery().
|
|
||||||
AggregateTypes(aggregateType).
|
|
||||||
SequenceGreater(sequences[aggregateType]).
|
|
||||||
SequenceLess(stmtSeq)
|
|
||||||
|
|
||||||
queriesAdded = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !queriesAdded {
|
if !queriesAdded {
|
||||||
@@ -214,16 +231,19 @@ func (h *StatementHandler) executeStmts(
|
|||||||
|
|
||||||
lastSuccessfulIdx := -1
|
lastSuccessfulIdx := -1
|
||||||
for i, stmt := range stmts {
|
for i, stmt := range stmts {
|
||||||
if stmt.Sequence <= sequences[stmt.AggregateType] {
|
for _, sequence := range sequences[stmt.AggregateType] {
|
||||||
continue
|
if stmt.Sequence <= sequence.sequence && stmt.InstanceID == sequence.instanceID {
|
||||||
}
|
continue
|
||||||
if stmt.PreviousSequence > 0 && stmt.PreviousSequence != sequences[stmt.AggregateType] {
|
}
|
||||||
logging.WithFields("projection", h.ProjectionName, "aggregateType", stmt.AggregateType, "sequence", stmt.Sequence, "prevSeq", stmt.PreviousSequence, "currentSeq", sequences[stmt.AggregateType]).Warn("sequences do not match")
|
if stmt.PreviousSequence > 0 && stmt.PreviousSequence != sequence.sequence && stmt.InstanceID == sequence.instanceID {
|
||||||
break
|
logging.WithFields("projection", h.ProjectionName, "aggregateType", stmt.AggregateType, "sequence", stmt.Sequence, "prevSeq", stmt.PreviousSequence, "currentSeq", sequences[stmt.AggregateType]).Warn("sequences do not match")
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err := h.executeStmt(tx, stmt)
|
err := h.executeStmt(tx, stmt)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
sequences[stmt.AggregateType], lastSuccessfulIdx = stmt.Sequence, i
|
updateSequences(sequences, stmt)
|
||||||
|
lastSuccessfulIdx = i
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +252,9 @@ func (h *StatementHandler) executeStmts(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
sequences[stmt.AggregateType], lastSuccessfulIdx = stmt.Sequence, i
|
updateSequences(sequences, stmt)
|
||||||
|
lastSuccessfulIdx = i
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
return lastSuccessfulIdx
|
return lastSuccessfulIdx
|
||||||
}
|
}
|
||||||
@@ -261,3 +283,16 @@ func (h *StatementHandler) executeStmt(tx *sql.Tx, stmt *handler.Statement) erro
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateSequences(sequences currentSequences, stmt *handler.Statement) {
|
||||||
|
for _, sequence := range sequences[stmt.AggregateType] {
|
||||||
|
if sequence.instanceID == stmt.InstanceID {
|
||||||
|
sequence.sequence = stmt.Sequence
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sequences[stmt.AggregateType] = append(sequences[stmt.AggregateType], &instanceSequence{
|
||||||
|
instanceID: stmt.InstanceID,
|
||||||
|
sequence: stmt.Sequence,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
"github.com/caos/zitadel/internal/eventstore/handler"
|
"github.com/caos/zitadel/internal/eventstore/handler"
|
||||||
@@ -97,13 +98,18 @@ func TestProjectionHandler_SearchQuery(t *testing.T) {
|
|||||||
return err == nil
|
return err == nil
|
||||||
},
|
},
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg", "instanceID"),
|
||||||
},
|
},
|
||||||
SearchQueryBuilder: eventstore.
|
SearchQueryBuilder: eventstore.
|
||||||
NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||||
AddQuery().
|
AddQuery().
|
||||||
AggregateTypes("testAgg").
|
AggregateTypes("testAgg").
|
||||||
SequenceGreater(5).
|
SequenceGreater(5).
|
||||||
|
InstanceID("instanceID").
|
||||||
|
Or().
|
||||||
|
AggregateTypes("testAgg").
|
||||||
|
SequenceGreater(0).
|
||||||
|
ExcludedInstanceID("instanceID").
|
||||||
Builder().
|
Builder().
|
||||||
Limit(5),
|
Limit(5),
|
||||||
},
|
},
|
||||||
@@ -225,7 +231,7 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectBegin(),
|
expectBegin(),
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg", "instanceID"),
|
||||||
expectRollback(),
|
expectRollback(),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
@@ -262,7 +268,7 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectBegin(),
|
expectBegin(),
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg", "instanceID"),
|
||||||
expectCommit(),
|
expectCommit(),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
@@ -287,6 +293,7 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
aggregateType: "agg",
|
aggregateType: "agg",
|
||||||
sequence: 7,
|
sequence: 7,
|
||||||
previousSequence: 5,
|
previousSequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
},
|
},
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
{
|
{
|
||||||
@@ -299,11 +306,11 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectBegin(),
|
expectBegin(),
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "agg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "agg", "instanceID"),
|
||||||
expectSavePoint(),
|
expectSavePoint(),
|
||||||
expectCreate("my_projection", []string{"col"}, []string{"$1"}),
|
expectCreate("my_projection", []string{"col"}, []string{"$1"}),
|
||||||
expectSavePointRelease(),
|
expectSavePointRelease(),
|
||||||
expectUpdateCurrentSequenceNoRows("my_sequences", "my_projection", 7, "agg"),
|
expectUpdateCurrentSequenceNoRows("my_sequences", "my_projection", 7, "agg", "instanceID"),
|
||||||
expectRollback(),
|
expectRollback(),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
@@ -328,6 +335,7 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
aggregateType: "agg",
|
aggregateType: "agg",
|
||||||
sequence: 7,
|
sequence: 7,
|
||||||
previousSequence: 5,
|
previousSequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
},
|
},
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
{
|
{
|
||||||
@@ -340,11 +348,11 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectBegin(),
|
expectBegin(),
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "agg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "agg", "instanceID"),
|
||||||
expectSavePoint(),
|
expectSavePoint(),
|
||||||
expectCreate("my_projection", []string{"col"}, []string{"$1"}),
|
expectCreate("my_projection", []string{"col"}, []string{"$1"}),
|
||||||
expectSavePointRelease(),
|
expectSavePointRelease(),
|
||||||
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "agg"),
|
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "agg", "instanceID"),
|
||||||
expectCommitErr(sql.ErrConnDone),
|
expectCommitErr(sql.ErrConnDone),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
@@ -368,14 +376,15 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
aggregateType: "testAgg",
|
aggregateType: "testAgg",
|
||||||
sequence: 7,
|
sequence: 7,
|
||||||
previousSequence: 5,
|
previousSequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectBegin(),
|
expectBegin(),
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg", "instanceID"),
|
||||||
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "testAgg"),
|
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "testAgg", "instanceID"),
|
||||||
expectCommit(),
|
expectCommit(),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
@@ -399,14 +408,15 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
aggregateType: "testAgg",
|
aggregateType: "testAgg",
|
||||||
sequence: 7,
|
sequence: 7,
|
||||||
previousSequence: 0,
|
previousSequence: 0,
|
||||||
|
instanceID: "instanceID",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectBegin(),
|
expectBegin(),
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg", "instanceID"),
|
||||||
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "testAgg"),
|
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "testAgg", "instanceID"),
|
||||||
expectCommit(),
|
expectCommit(),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
@@ -423,6 +433,7 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
AggregateType: "testAgg",
|
AggregateType: "testAgg",
|
||||||
Sequence: 6,
|
Sequence: 6,
|
||||||
PreviousAggregateSequence: 5,
|
PreviousAggregateSequence: 5,
|
||||||
|
InstanceID: "instanceID",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -435,6 +446,7 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
aggregateType: "testAgg",
|
aggregateType: "testAgg",
|
||||||
sequence: 7,
|
sequence: 7,
|
||||||
previousSequence: 0,
|
previousSequence: 0,
|
||||||
|
instanceID: "instanceID",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
reduce: testReduce(),
|
reduce: testReduce(),
|
||||||
@@ -442,8 +454,8 @@ func TestStatementHandler_Update(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectBegin(),
|
expectBegin(),
|
||||||
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg"),
|
expectCurrentSequence("my_sequences", "my_projection", 5, "testAgg", "instanceID"),
|
||||||
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "testAgg"),
|
expectUpdateCurrentSequence("my_sequences", "my_projection", 7, "testAgg", "instanceID"),
|
||||||
expectCommit(),
|
expectCommit(),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
@@ -537,7 +549,9 @@ func TestProjectionHandler_fetchPreviousStmts(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
reduce: testReduce(),
|
reduce: testReduce(),
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"testAgg": 5,
|
"testAgg": []*instanceSequence{
|
||||||
|
{sequence: 5},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
stmtSeq: 6,
|
stmtSeq: 6,
|
||||||
},
|
},
|
||||||
@@ -560,7 +574,9 @@ func TestProjectionHandler_fetchPreviousStmts(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
reduce: testReduce(),
|
reduce: testReduce(),
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"testAgg": 5,
|
"testAgg": []*instanceSequence{
|
||||||
|
{sequence: 5},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
stmtSeq: 6,
|
stmtSeq: 6,
|
||||||
},
|
},
|
||||||
@@ -582,7 +598,9 @@ func TestProjectionHandler_fetchPreviousStmts(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
reduce: testReduce(),
|
reduce: testReduce(),
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"testAgg": 5,
|
"testAgg": []*instanceSequence{
|
||||||
|
{sequence: 5},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
stmtSeq: 10,
|
stmtSeq: 10,
|
||||||
},
|
},
|
||||||
@@ -626,7 +644,9 @@ func TestProjectionHandler_fetchPreviousStmts(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
reduce: testReduceErr(errReduce),
|
reduce: testReduceErr(errReduce),
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"testAgg": 5,
|
"testAgg": []*instanceSequence{
|
||||||
|
{sequence: 5},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
stmtSeq: 10,
|
stmtSeq: 10,
|
||||||
},
|
},
|
||||||
@@ -667,7 +687,7 @@ func TestProjectionHandler_fetchPreviousStmts(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
aggregates: tt.fields.aggregates,
|
aggregates: tt.fields.aggregates,
|
||||||
}
|
}
|
||||||
stmts, err := h.fetchPreviousStmts(tt.args.ctx, tt.args.stmtSeq, tt.args.sequences, tt.args.reduce)
|
stmts, err := h.fetchPreviousStmts(tt.args.ctx, tt.args.stmtSeq, "", tt.args.sequences, tt.args.reduce)
|
||||||
if !tt.want.isErr(err) {
|
if !tt.want.isErr(err) {
|
||||||
t.Errorf("ProjectionHandler.prepareBulkStmts() error = %v", err)
|
t.Errorf("ProjectionHandler.prepareBulkStmts() error = %v", err)
|
||||||
return
|
return
|
||||||
@@ -720,7 +740,9 @@ func TestStatementHandler_executeStmts(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 5,
|
"agg": []*instanceSequence{
|
||||||
|
{sequence: 5},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -762,7 +784,9 @@ func TestStatementHandler_executeStmts(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 2,
|
"agg": []*instanceSequence{
|
||||||
|
{sequence: 2},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -824,7 +848,9 @@ func TestStatementHandler_executeStmts(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 2,
|
"agg": []*instanceSequence{
|
||||||
|
{sequence: 2},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -891,7 +917,9 @@ func TestStatementHandler_executeStmts(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 2,
|
"agg": []*instanceSequence{
|
||||||
|
{sequence: 2},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -979,7 +1007,9 @@ func TestStatementHandler_executeStmts(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 2,
|
"agg": []*instanceSequence{
|
||||||
|
{sequence: 2},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -1309,9 +1339,7 @@ func TestStatementHandler_currentSequence(t *testing.T) {
|
|||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectCurrentSequenceNoRows("my_table", "my_projection"),
|
expectCurrentSequenceNoRows("my_table", "my_projection"),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{},
|
||||||
"agg": 0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1331,9 +1359,7 @@ func TestStatementHandler_currentSequence(t *testing.T) {
|
|||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectCurrentSequenceScanErr("my_table", "my_projection"),
|
expectCurrentSequenceScanErr("my_table", "my_projection"),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{},
|
||||||
"agg": 0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1351,10 +1377,15 @@ func TestStatementHandler_currentSequence(t *testing.T) {
|
|||||||
return errors.Is(err, nil)
|
return errors.Is(err, nil)
|
||||||
},
|
},
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectCurrentSequence("my_table", "my_projection", 5, "agg"),
|
expectCurrentSequence("my_table", "my_projection", 5, "agg", "instanceID"),
|
||||||
},
|
},
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 5,
|
"agg": []*instanceSequence{
|
||||||
|
{
|
||||||
|
sequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1404,9 +1435,7 @@ func TestStatementHandler_currentSequence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, aggregateType := range tt.fields.aggregates {
|
for _, aggregateType := range tt.fields.aggregates {
|
||||||
if seq[aggregateType] != tt.want.sequences[aggregateType] {
|
assert.Equal(t, tt.want.sequences[aggregateType], seq[aggregateType])
|
||||||
t.Errorf("unexpected sequence in aggregate type %s: want %d got %d", aggregateType, tt.want.sequences[aggregateType], seq[aggregateType])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1440,7 +1469,12 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 5,
|
"agg": []*instanceSequence{
|
||||||
|
{
|
||||||
|
sequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -1448,7 +1482,7 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
return errors.Is(err, sql.ErrConnDone)
|
return errors.Is(err, sql.ErrConnDone)
|
||||||
},
|
},
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectUpdateCurrentSequenceErr("my_table", "my_projection", 5, sql.ErrConnDone, "agg"),
|
expectUpdateCurrentSequenceErr("my_table", "my_projection", 5, sql.ErrConnDone, "agg", "instanceID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1461,7 +1495,12 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 5,
|
"agg": []*instanceSequence{
|
||||||
|
{
|
||||||
|
sequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -1469,7 +1508,7 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
return errors.As(err, &errSeqNotUpdated)
|
return errors.As(err, &errSeqNotUpdated)
|
||||||
},
|
},
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectUpdateCurrentSequenceNoRows("my_table", "my_projection", 5, "agg"),
|
expectUpdateCurrentSequenceNoRows("my_table", "my_projection", 5, "agg", "instanceID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1482,7 +1521,12 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 5,
|
"agg": []*instanceSequence{
|
||||||
|
{
|
||||||
|
sequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -1490,7 +1534,7 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
return err == nil
|
return err == nil
|
||||||
},
|
},
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectUpdateCurrentSequence("my_table", "my_projection", 5, "agg"),
|
expectUpdateCurrentSequence("my_table", "my_projection", 5, "agg", "instanceID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1503,8 +1547,18 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
sequences: currentSequences{
|
sequences: currentSequences{
|
||||||
"agg": 5,
|
"agg": []*instanceSequence{
|
||||||
"agg2": 6,
|
{
|
||||||
|
sequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"agg2": []*instanceSequence{
|
||||||
|
{
|
||||||
|
sequence: 6,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
want: want{
|
want: want{
|
||||||
@@ -1513,9 +1567,19 @@ func TestStatementHandler_updateCurrentSequence(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectUpdateTwoCurrentSequence("my_table", "my_projection", currentSequences{
|
expectUpdateTwoCurrentSequence("my_table", "my_projection", currentSequences{
|
||||||
"agg": 5,
|
"agg": []*instanceSequence{
|
||||||
"agg2": 6},
|
{
|
||||||
),
|
sequence: 5,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"agg2": []*instanceSequence{
|
||||||
|
{
|
||||||
|
sequence: 6,
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -15,15 +15,15 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
lockStmtFormat = "INSERT INTO %[1]s" +
|
lockStmtFormat = "INSERT INTO %[1]s" +
|
||||||
" (locker_id, locked_until, projection_name) VALUES ($1, now()+$2::INTERVAL, $3)" +
|
" (locker_id, locked_until, projection_name, instance_id) VALUES ($1, now()+$2::INTERVAL, $3, $4)" +
|
||||||
" ON CONFLICT (projection_name)" +
|
" ON CONFLICT (projection_name, instance_id)" +
|
||||||
" DO UPDATE SET locker_id = $1, locked_until = now()+$2::INTERVAL" +
|
" DO UPDATE SET locker_id = $1, locked_until = now()+$2::INTERVAL" +
|
||||||
" WHERE %[1]s.projection_name = $3 AND (%[1]s.locker_id = $1 OR %[1]s.locked_until < now())"
|
" WHERE %[1]s.projection_name = $3 AND %[1]s.instance_id = $4 AND (%[1]s.locker_id = $1 OR %[1]s.locked_until < now())"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Locker interface {
|
type Locker interface {
|
||||||
Lock(ctx context.Context, lockDuration time.Duration) <-chan error
|
Lock(ctx context.Context, lockDuration time.Duration, instanceID string) <-chan error
|
||||||
Unlock() error
|
Unlock(instanceID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type locker struct {
|
type locker struct {
|
||||||
@@ -47,18 +47,18 @@ func NewLocker(client *sql.DB, lockTable, projectionName string) Locker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *locker) Lock(ctx context.Context, lockDuration time.Duration) <-chan error {
|
func (h *locker) Lock(ctx context.Context, lockDuration time.Duration, instanceID string) <-chan error {
|
||||||
errs := make(chan error)
|
errs := make(chan error)
|
||||||
go h.handleLock(ctx, errs, lockDuration)
|
go h.handleLock(ctx, errs, lockDuration, instanceID)
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *locker) handleLock(ctx context.Context, errs chan error, lockDuration time.Duration) {
|
func (h *locker) handleLock(ctx context.Context, errs chan error, lockDuration time.Duration, instanceID string) {
|
||||||
renewLock := time.NewTimer(0)
|
renewLock := time.NewTimer(0)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-renewLock.C:
|
case <-renewLock.C:
|
||||||
errs <- h.renewLock(ctx, lockDuration)
|
errs <- h.renewLock(ctx, lockDuration, instanceID)
|
||||||
//refresh the lock 500ms before it times out. 500ms should be enough for one transaction
|
//refresh the lock 500ms before it times out. 500ms should be enough for one transaction
|
||||||
renewLock.Reset(lockDuration - (500 * time.Millisecond))
|
renewLock.Reset(lockDuration - (500 * time.Millisecond))
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
@@ -69,9 +69,9 @@ func (h *locker) handleLock(ctx context.Context, errs chan error, lockDuration t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *locker) renewLock(ctx context.Context, lockDuration time.Duration) error {
|
func (h *locker) renewLock(ctx context.Context, lockDuration time.Duration, instanceID string) error {
|
||||||
//the unit of crdb interval is seconds (https://www.cockroachlabs.com/docs/stable/interval.html).
|
//the unit of crdb interval is seconds (https://www.cockroachlabs.com/docs/stable/interval.html).
|
||||||
res, err := h.client.Exec(h.lockStmt, h.workerName, lockDuration.Seconds(), h.projectionName)
|
res, err := h.client.Exec(h.lockStmt, h.workerName, lockDuration.Seconds(), h.projectionName, instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.ThrowInternal(err, "CRDB-uaDoR", "unable to execute lock")
|
return errors.ThrowInternal(err, "CRDB-uaDoR", "unable to execute lock")
|
||||||
}
|
}
|
||||||
@@ -83,8 +83,8 @@ func (h *locker) renewLock(ctx context.Context, lockDuration time.Duration) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *locker) Unlock() error {
|
func (h *locker) Unlock(instanceID string) error {
|
||||||
_, err := h.client.Exec(h.lockStmt, h.workerName, float64(0), h.projectionName)
|
_, err := h.client.Exec(h.lockStmt, h.workerName, float64(0), h.projectionName, instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.ThrowUnknown(err, "CRDB-JjfwO", "unlock failed")
|
return errors.ThrowUnknown(err, "CRDB-JjfwO", "unlock failed")
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,7 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
|||||||
lockDuration time.Duration
|
lockDuration time.Duration
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
errMock *errsMock
|
errMock *errsMock
|
||||||
|
instanceID string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -42,9 +43,9 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
|||||||
name: "lock fails",
|
name: "lock fails",
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectLock(lockTable, workerName, 2),
|
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||||
expectLock(lockTable, workerName, 2),
|
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||||
expectLockErr(lockTable, workerName, 2, errLock),
|
expectLockErr(lockTable, workerName, 2, "instanceID", errLock),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
@@ -55,14 +56,15 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
|||||||
successfulIters: 2,
|
successfulIters: 2,
|
||||||
shouldErr: true,
|
shouldErr: true,
|
||||||
},
|
},
|
||||||
|
instanceID: "instanceID",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectLock(lockTable, workerName, 2),
|
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||||
expectLock(lockTable, workerName, 2),
|
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
@@ -72,6 +74,7 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
|||||||
errs: make(chan error),
|
errs: make(chan error),
|
||||||
successfulIters: 2,
|
successfulIters: 2,
|
||||||
},
|
},
|
||||||
|
instanceID: "instanceID",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -96,7 +99,7 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
|||||||
|
|
||||||
go tt.args.errMock.handleErrs(t, cancel)
|
go tt.args.errMock.handleErrs(t, cancel)
|
||||||
|
|
||||||
go h.handleLock(ctx, tt.args.errMock.errs, tt.args.lockDuration)
|
go h.handleLock(ctx, tt.args.errMock.errs, tt.args.lockDuration, tt.args.instanceID)
|
||||||
|
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
||||||
@@ -115,6 +118,7 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
lockDuration time.Duration
|
lockDuration time.Duration
|
||||||
|
instanceID string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -125,7 +129,7 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
|||||||
name: "lock fails",
|
name: "lock fails",
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectLockErr(lockTable, workerName, 1, sql.ErrTxDone),
|
expectLockErr(lockTable, workerName, 1, "instanceID", sql.ErrTxDone),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
return errors.Is(err, sql.ErrTxDone)
|
return errors.Is(err, sql.ErrTxDone)
|
||||||
@@ -133,13 +137,14 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
lockDuration: 1 * time.Second,
|
lockDuration: 1 * time.Second,
|
||||||
|
instanceID: "instanceID",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "lock no rows",
|
name: "lock no rows",
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectLockNoRows(lockTable, workerName, 2),
|
expectLockNoRows(lockTable, workerName, 2, "instanceID"),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
return errors.As(err, &renewNoRowsAffectedErr)
|
return errors.As(err, &renewNoRowsAffectedErr)
|
||||||
@@ -147,13 +152,14 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
lockDuration: 2 * time.Second,
|
lockDuration: 2 * time.Second,
|
||||||
|
instanceID: "instanceID",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectLock(lockTable, workerName, 3),
|
expectLock(lockTable, workerName, 3, "instanceID"),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
return errors.Is(err, nil)
|
return errors.Is(err, nil)
|
||||||
@@ -161,6 +167,7 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
lockDuration: 3 * time.Second,
|
lockDuration: 3 * time.Second,
|
||||||
|
instanceID: "instanceID",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -181,7 +188,7 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
|||||||
expectation(mock)
|
expectation(mock)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.renewLock(context.Background(), tt.args.lockDuration)
|
err = h.renewLock(context.Background(), tt.args.lockDuration, tt.args.instanceID)
|
||||||
if !tt.want.isErr(err) {
|
if !tt.want.isErr(err) {
|
||||||
t.Errorf("unexpected error = %v", err)
|
t.Errorf("unexpected error = %v", err)
|
||||||
}
|
}
|
||||||
@@ -199,15 +206,22 @@ func TestStatementHandler_Unlock(t *testing.T) {
|
|||||||
expectations []mockExpectation
|
expectations []mockExpectation
|
||||||
isErr func(err error) bool
|
isErr func(err error) bool
|
||||||
}
|
}
|
||||||
|
type args struct {
|
||||||
|
instanceID string
|
||||||
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
args args
|
||||||
want want
|
want want
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "unlock fails",
|
name: "unlock fails",
|
||||||
|
args: args{
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectLockErr(lockTable, workerName, 0, sql.ErrTxDone),
|
expectLockErr(lockTable, workerName, 0, "instanceID", sql.ErrTxDone),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
return errors.Is(err, sql.ErrTxDone)
|
return errors.Is(err, sql.ErrTxDone)
|
||||||
@@ -216,9 +230,12 @@ func TestStatementHandler_Unlock(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
|
args: args{
|
||||||
|
instanceID: "instanceID",
|
||||||
|
},
|
||||||
want: want{
|
want: want{
|
||||||
expectations: []mockExpectation{
|
expectations: []mockExpectation{
|
||||||
expectLock(lockTable, workerName, 0),
|
expectLock(lockTable, workerName, 0, "instanceID"),
|
||||||
},
|
},
|
||||||
isErr: func(err error) bool {
|
isErr: func(err error) bool {
|
||||||
return errors.Is(err, nil)
|
return errors.Is(err, nil)
|
||||||
@@ -243,7 +260,7 @@ func TestStatementHandler_Unlock(t *testing.T) {
|
|||||||
expectation(mock)
|
expectation(mock)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.Unlock()
|
err = h.Unlock(tt.args.instanceID)
|
||||||
if !tt.want.isErr(err) {
|
if !tt.want.isErr(err) {
|
||||||
t.Errorf("unexpected error = %v", err)
|
t.Errorf("unexpected error = %v", err)
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/eventstore"
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const systemID = "system"
|
||||||
|
|
||||||
type ProjectionHandlerConfig struct {
|
type ProjectionHandlerConfig struct {
|
||||||
HandlerConfig
|
HandlerConfig
|
||||||
ProjectionName string
|
ProjectionName string
|
||||||
@@ -27,10 +29,10 @@ type Update func(context.Context, []*Statement, Reduce) (unexecutedStmts []*Stat
|
|||||||
type Reduce func(eventstore.Event) (*Statement, error)
|
type Reduce func(eventstore.Event) (*Statement, error)
|
||||||
|
|
||||||
//Lock is used for mutex handling if needed on the projection
|
//Lock is used for mutex handling if needed on the projection
|
||||||
type Lock func(context.Context, time.Duration) <-chan error
|
type Lock func(context.Context, time.Duration, string) <-chan error
|
||||||
|
|
||||||
//Unlock releases the mutex of the projection
|
//Unlock releases the mutex of the projection
|
||||||
type Unlock func() error
|
type Unlock func(string) error
|
||||||
|
|
||||||
//SearchQuery generates the search query to lookup for events
|
//SearchQuery generates the search query to lookup for events
|
||||||
type SearchQuery func() (query *eventstore.SearchQueryBuilder, queryLimit uint64, err error)
|
type SearchQuery func() (query *eventstore.SearchQueryBuilder, queryLimit uint64, err error)
|
||||||
@@ -183,7 +185,7 @@ func (h *ProjectionHandler) bulk(
|
|||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
errs := lock(ctx, h.requeueAfter)
|
errs := lock(ctx, h.requeueAfter, systemID)
|
||||||
//wait until projection is locked
|
//wait until projection is locked
|
||||||
if err, ok := <-errs; err != nil || !ok {
|
if err, ok := <-errs; err != nil || !ok {
|
||||||
logging.WithFields("projection", h.ProjectionName).OnError(err).Warn("initial lock failed")
|
logging.WithFields("projection", h.ProjectionName).OnError(err).Warn("initial lock failed")
|
||||||
@@ -194,7 +196,7 @@ func (h *ProjectionHandler) bulk(
|
|||||||
execErr := executeBulk(ctx)
|
execErr := executeBulk(ctx)
|
||||||
logging.WithFields("projection", h.ProjectionName).OnError(execErr).Warn("unable to execute")
|
logging.WithFields("projection", h.ProjectionName).OnError(execErr).Warn("unable to execute")
|
||||||
|
|
||||||
unlockErr := unlock()
|
unlockErr := unlock(systemID)
|
||||||
logging.WithFields("projection", h.ProjectionName).OnError(unlockErr).Warn("unable to unlock")
|
logging.WithFields("projection", h.ProjectionName).OnError(unlockErr).Warn("unable to unlock")
|
||||||
|
|
||||||
if execErr != nil {
|
if execErr != nil {
|
||||||
|
@@ -912,7 +912,7 @@ type lockMock struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *lockMock) lock() Lock {
|
func (m *lockMock) lock() Lock {
|
||||||
return func(ctx context.Context, _ time.Duration) <-chan error {
|
return func(ctx context.Context, _ time.Duration, _ string) <-chan error {
|
||||||
m.callCount++
|
m.callCount++
|
||||||
errs := make(chan error)
|
errs := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
@@ -955,7 +955,7 @@ type unlockMock struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *unlockMock) unlock() Unlock {
|
func (m *unlockMock) unlock() Unlock {
|
||||||
return func() error {
|
return func(instanceID string) error {
|
||||||
m.callCount++
|
m.callCount++
|
||||||
return m.err
|
return m.err
|
||||||
}
|
}
|
||||||
|
@@ -50,6 +50,8 @@ const (
|
|||||||
OperationIn
|
OperationIn
|
||||||
//OperationJSONContains checks if a stored value matches the given json
|
//OperationJSONContains checks if a stored value matches the given json
|
||||||
OperationJSONContains
|
OperationJSONContains
|
||||||
|
//OperationNotIn checks if a stored value does not match one of the passed value list
|
||||||
|
OperationNotIn
|
||||||
|
|
||||||
operationCount
|
operationCount
|
||||||
)
|
)
|
||||||
|
@@ -288,8 +288,11 @@ func (db *CRDB) columnName(col repository.Field) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *CRDB) conditionFormat(operation repository.Operation) string {
|
func (db *CRDB) conditionFormat(operation repository.Operation) string {
|
||||||
if operation == repository.OperationIn {
|
switch operation {
|
||||||
|
case repository.OperationIn:
|
||||||
return "%s %s ANY(?)"
|
return "%s %s ANY(?)"
|
||||||
|
case repository.OperationNotIn:
|
||||||
|
return "%s %s ALL(?)"
|
||||||
}
|
}
|
||||||
return "%s %s ?"
|
return "%s %s ?"
|
||||||
}
|
}
|
||||||
@@ -304,6 +307,8 @@ func (db *CRDB) operation(operation repository.Operation) string {
|
|||||||
return "<"
|
return "<"
|
||||||
case repository.OperationJSONContains:
|
case repository.OperationJSONContains:
|
||||||
return "@>"
|
return "@>"
|
||||||
|
case repository.OperationNotIn:
|
||||||
|
return "<>"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,8 @@ type SearchQuery struct {
|
|||||||
builder *SearchQueryBuilder
|
builder *SearchQueryBuilder
|
||||||
aggregateTypes []AggregateType
|
aggregateTypes []AggregateType
|
||||||
aggregateIDs []string
|
aggregateIDs []string
|
||||||
|
instanceID string
|
||||||
|
excludedInstanceIDs []string
|
||||||
eventSequenceGreater uint64
|
eventSequenceGreater uint64
|
||||||
eventSequenceLess uint64
|
eventSequenceLess uint64
|
||||||
eventTypes []EventType
|
eventTypes []EventType
|
||||||
@@ -91,9 +93,9 @@ func (builder *SearchQueryBuilder) ResourceOwner(resourceOwner string) *SearchQu
|
|||||||
}
|
}
|
||||||
|
|
||||||
//InstanceID defines the instanceID (system) of the events
|
//InstanceID defines the instanceID (system) of the events
|
||||||
func (factory *SearchQueryBuilder) InstanceID(instanceID string) *SearchQueryBuilder {
|
func (builder *SearchQueryBuilder) InstanceID(instanceID string) *SearchQueryBuilder {
|
||||||
factory.instanceID = instanceID
|
builder.instanceID = instanceID
|
||||||
return factory
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
//OrderDesc changes the sorting order of the returned events to descending
|
//OrderDesc changes the sorting order of the returned events to descending
|
||||||
@@ -149,6 +151,18 @@ func (query *SearchQuery) AggregateIDs(ids ...string) *SearchQuery {
|
|||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//InstanceID filters for events with the given instanceID
|
||||||
|
func (query *SearchQuery) InstanceID(instanceID string) *SearchQuery {
|
||||||
|
query.instanceID = instanceID
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
//ExcludedInstanceID filters for events not having the given instanceIDs
|
||||||
|
func (query *SearchQuery) ExcludedInstanceID(instanceIDs ...string) *SearchQuery {
|
||||||
|
query.excludedInstanceIDs = instanceIDs
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
//EventTypes filters for events with the given event types
|
//EventTypes filters for events with the given event types
|
||||||
func (query *SearchQuery) EventTypes(types ...EventType) *SearchQuery {
|
func (query *SearchQuery) EventTypes(types ...EventType) *SearchQuery {
|
||||||
query.eventTypes = types
|
query.eventTypes = types
|
||||||
@@ -180,6 +194,9 @@ func (query *SearchQuery) matches(event Event) bool {
|
|||||||
if ok := isAggregateIDs(event.Aggregate(), query.aggregateIDs...); len(query.aggregateIDs) > 0 && !ok {
|
if ok := isAggregateIDs(event.Aggregate(), query.aggregateIDs...); len(query.aggregateIDs) > 0 && !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if event.Aggregate().InstanceID != "" && query.instanceID != "" && event.Aggregate().InstanceID != query.instanceID {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if ok := isEventTypes(event, query.eventTypes...); len(query.eventTypes) > 0 && !ok {
|
if ok := isEventTypes(event, query.eventTypes...); len(query.eventTypes) > 0 && !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -203,6 +220,8 @@ func (builder *SearchQueryBuilder) build(instanceID string) (*repository.SearchQ
|
|||||||
query.eventDataFilter,
|
query.eventDataFilter,
|
||||||
query.eventSequenceGreaterFilter,
|
query.eventSequenceGreaterFilter,
|
||||||
query.eventSequenceLessFilter,
|
query.eventSequenceLessFilter,
|
||||||
|
query.instanceIDFilter,
|
||||||
|
query.excludedInstanceIDFilter,
|
||||||
query.builder.resourceOwnerFilter,
|
query.builder.resourceOwnerFilter,
|
||||||
query.builder.instanceIDFilter,
|
query.builder.instanceIDFilter,
|
||||||
} {
|
} {
|
||||||
@@ -281,6 +300,20 @@ func (query *SearchQuery) eventSequenceLessFilter() *repository.Filter {
|
|||||||
return repository.NewFilter(repository.FieldSequence, query.eventSequenceLess, sortOrder)
|
return repository.NewFilter(repository.FieldSequence, query.eventSequenceLess, sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (query *SearchQuery) instanceIDFilter() *repository.Filter {
|
||||||
|
if query.instanceID == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return repository.NewFilter(repository.FieldInstanceID, query.instanceID, repository.OperationEquals)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (query *SearchQuery) excludedInstanceIDFilter() *repository.Filter {
|
||||||
|
if len(query.excludedInstanceIDs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return repository.NewFilter(repository.FieldInstanceID, query.excludedInstanceIDs, repository.OperationNotIn)
|
||||||
|
}
|
||||||
|
|
||||||
func (builder *SearchQueryBuilder) resourceOwnerFilter() *repository.Filter {
|
func (builder *SearchQueryBuilder) resourceOwnerFilter() *repository.Filter {
|
||||||
if builder.resourceOwner == "" {
|
if builder.resourceOwner == "" {
|
||||||
return nil
|
return nil
|
||||||
|
@@ -12,7 +12,6 @@ import (
|
|||||||
type Eventstore interface {
|
type Eventstore interface {
|
||||||
Health(ctx context.Context) error
|
Health(ctx context.Context) error
|
||||||
FilterEvents(ctx context.Context, searchQuery *models.SearchQuery) (events []*models.Event, err error)
|
FilterEvents(ctx context.Context, searchQuery *models.SearchQuery) (events []*models.Event, err error)
|
||||||
LatestSequence(ctx context.Context, searchQuery *models.SearchQueryFactory) (uint64, error)
|
|
||||||
Subscribe(aggregates ...models.AggregateType) *Subscription
|
Subscribe(aggregates ...models.AggregateType) *Subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,13 +34,6 @@ func (es *eventstore) FilterEvents(ctx context.Context, searchQuery *models.Sear
|
|||||||
return es.repo.Filter(ctx, models.FactoryFromSearchQuery(searchQuery))
|
return es.repo.Filter(ctx, models.FactoryFromSearchQuery(searchQuery))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *eventstore) LatestSequence(ctx context.Context, queryFactory *models.SearchQueryFactory) (uint64, error) {
|
|
||||||
sequenceFactory := *queryFactory
|
|
||||||
sequenceFactory = *(&sequenceFactory).Columns(models.Columns_Max_Sequence)
|
|
||||||
sequenceFactory = *(&sequenceFactory).SequenceGreater(0)
|
|
||||||
return es.repo.LatestSequence(ctx, &sequenceFactory)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (es *eventstore) Health(ctx context.Context) error {
|
func (es *eventstore) Health(ctx context.Context) error {
|
||||||
return es.repo.Health(ctx)
|
return es.repo.Health(ctx)
|
||||||
}
|
}
|
||||||
|
@@ -12,16 +12,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
selectEscaped = `SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore\.events WHERE aggregate_type = \$1`
|
selectEscaped = `SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore\.events WHERE \( aggregate_type = \$1`
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
eventColumns = []string{"creation_date", "event_type", "event_sequence", "previous_aggregate_sequence", "event_data", "editor_service", "editor_user", "resource_owner", "instance_id", "aggregate_type", "aggregate_id", "aggregate_version"}
|
eventColumns = []string{"creation_date", "event_type", "event_sequence", "previous_aggregate_sequence", "event_data", "editor_service", "editor_user", "resource_owner", "instance_id", "aggregate_type", "aggregate_id", "aggregate_version"}
|
||||||
expectedFilterEventsLimitFormat = regexp.MustCompile(selectEscaped + ` ORDER BY event_sequence LIMIT \$2`).String()
|
expectedFilterEventsLimitFormat = regexp.MustCompile(selectEscaped + ` \) ORDER BY event_sequence LIMIT \$2`).String()
|
||||||
expectedFilterEventsDescFormat = regexp.MustCompile(selectEscaped + ` ORDER BY event_sequence DESC`).String()
|
expectedFilterEventsDescFormat = regexp.MustCompile(selectEscaped + ` \) ORDER BY event_sequence DESC`).String()
|
||||||
expectedFilterEventsAggregateIDLimit = regexp.MustCompile(selectEscaped + ` AND aggregate_id = \$2 ORDER BY event_sequence LIMIT \$3`).String()
|
expectedFilterEventsAggregateIDLimit = regexp.MustCompile(selectEscaped + ` AND aggregate_id = \$2 \) ORDER BY event_sequence LIMIT \$3`).String()
|
||||||
expectedFilterEventsAggregateIDTypeLimit = regexp.MustCompile(selectEscaped + ` AND aggregate_id = \$2 ORDER BY event_sequence LIMIT \$3`).String()
|
expectedFilterEventsAggregateIDTypeLimit = regexp.MustCompile(selectEscaped + ` AND aggregate_id = \$2 \) ORDER BY event_sequence LIMIT \$3`).String()
|
||||||
expectedGetAllEvents = regexp.MustCompile(selectEscaped + ` ORDER BY event_sequence`).String()
|
expectedGetAllEvents = regexp.MustCompile(selectEscaped + ` \) ORDER BY event_sequence`).String()
|
||||||
|
|
||||||
expectedInsertStatement = regexp.MustCompile(`INSERT INTO eventstore\.events ` +
|
expectedInsertStatement = regexp.MustCompile(`INSERT INTO eventstore\.events ` +
|
||||||
`\(event_type, aggregate_type, aggregate_id, aggregate_version, creation_date, event_data, editor_user, editor_service, resource_owner, instance_id, previous_aggregate_sequence, previous_aggregate_type_sequence\) ` +
|
`\(event_type, aggregate_type, aggregate_id, aggregate_version, creation_date, event_data, editor_user, editor_service, resource_owner, instance_id, previous_aggregate_sequence, previous_aggregate_type_sequence\) ` +
|
||||||
@@ -172,14 +172,14 @@ func (db *dbMock) expectFilterEventsError(returnedErr error) *dbMock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *dbMock) expectLatestSequenceFilter(aggregateType string, sequence Sequence) *dbMock {
|
func (db *dbMock) expectLatestSequenceFilter(aggregateType string, sequence Sequence) *dbMock {
|
||||||
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events WHERE aggregate_type = \$1`).
|
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events WHERE \( aggregate_type = \$1 \)`).
|
||||||
WithArgs(aggregateType).
|
WithArgs(aggregateType).
|
||||||
WillReturnRows(sqlmock.NewRows([]string{"max_sequence"}).AddRow(sequence))
|
WillReturnRows(sqlmock.NewRows([]string{"max_sequence"}).AddRow(sequence))
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *dbMock) expectLatestSequenceFilterError(aggregateType string, err error) *dbMock {
|
func (db *dbMock) expectLatestSequenceFilterError(aggregateType string, err error) *dbMock {
|
||||||
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events WHERE aggregate_type = \$1`).
|
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events WHERE \( aggregate_type = \$1 \)`).
|
||||||
WithArgs(aggregateType).WillReturnError(err)
|
WithArgs(aggregateType).WillReturnError(err)
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,7 @@ func TestSQL_Filter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
events: &mockEvents{t: t},
|
events: &mockEvents{t: t},
|
||||||
searchQuery: es_models.NewSearchQueryFactory("user").Limit(34),
|
searchQuery: es_models.NewSearchQueryFactory().Limit(34).AddQuery().AggregateTypes("user").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
eventsLen: 3,
|
eventsLen: 3,
|
||||||
@@ -55,7 +55,7 @@ func TestSQL_Filter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
events: &mockEvents{t: t},
|
events: &mockEvents{t: t},
|
||||||
searchQuery: es_models.NewSearchQueryFactory("user").OrderDesc(),
|
searchQuery: es_models.NewSearchQueryFactory().OrderDesc().AddQuery().AggregateTypes("user").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
eventsLen: 34,
|
eventsLen: 34,
|
||||||
@@ -69,7 +69,7 @@ func TestSQL_Filter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
events: &mockEvents{t: t},
|
events: &mockEvents{t: t},
|
||||||
searchQuery: es_models.NewSearchQueryFactory("nonAggregate"),
|
searchQuery: es_models.NewSearchQueryFactory().AddQuery().AggregateTypes("nonAggregate").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@@ -83,7 +83,7 @@ func TestSQL_Filter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
events: &mockEvents{t: t},
|
events: &mockEvents{t: t},
|
||||||
searchQuery: es_models.NewSearchQueryFactory("user"),
|
searchQuery: es_models.NewSearchQueryFactory().AddQuery().AggregateTypes("user").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
@@ -97,7 +97,7 @@ func TestSQL_Filter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
events: &mockEvents{t: t},
|
events: &mockEvents{t: t},
|
||||||
searchQuery: es_models.NewSearchQueryFactory("user").Limit(5).AggregateIDs("hop"),
|
searchQuery: es_models.NewSearchQueryFactory().Limit(5).AddQuery().AggregateTypes("user").AggregateIDs("hop").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
@@ -111,7 +111,7 @@ func TestSQL_Filter(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
events: &mockEvents{t: t},
|
events: &mockEvents{t: t},
|
||||||
searchQuery: es_models.NewSearchQueryFactory("user").Limit(5).AggregateIDs("hop"),
|
searchQuery: es_models.NewSearchQueryFactory().Limit(5).AddQuery().AggregateTypes("user").AggregateIDs("hop").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
@@ -176,7 +176,7 @@ func TestSQL_LatestSequence(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no events for aggregate",
|
name: "no events for aggregate",
|
||||||
args: args{
|
args: args{
|
||||||
searchQuery: es_models.NewSearchQueryFactory("idiot").Columns(es_models.Columns_Max_Sequence),
|
searchQuery: es_models.NewSearchQueryFactory().Columns(es_models.Columns_Max_Sequence).AddQuery().AggregateTypes("idiot").Factory(),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
client: mockDB(t).expectLatestSequenceFilterError("idiot", sql.ErrNoRows),
|
client: mockDB(t).expectLatestSequenceFilterError("idiot", sql.ErrNoRows),
|
||||||
@@ -189,7 +189,7 @@ func TestSQL_LatestSequence(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "sql query error",
|
name: "sql query error",
|
||||||
args: args{
|
args: args{
|
||||||
searchQuery: es_models.NewSearchQueryFactory("idiot").Columns(es_models.Columns_Max_Sequence),
|
searchQuery: es_models.NewSearchQueryFactory().Columns(es_models.Columns_Max_Sequence).AddQuery().AggregateTypes("idiot").Factory(),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
client: mockDB(t).expectLatestSequenceFilterError("idiot", sql.ErrConnDone),
|
client: mockDB(t).expectLatestSequenceFilterError("idiot", sql.ErrConnDone),
|
||||||
@@ -203,7 +203,7 @@ func TestSQL_LatestSequence(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "events for aggregate found",
|
name: "events for aggregate found",
|
||||||
args: args{
|
args: args{
|
||||||
searchQuery: es_models.NewSearchQueryFactory("user").Columns(es_models.Columns_Max_Sequence),
|
searchQuery: es_models.NewSearchQueryFactory().Columns(es_models.Columns_Max_Sequence).AddQuery().AggregateTypes("user").Factory(),
|
||||||
},
|
},
|
||||||
fields: fields{
|
fields: fields{
|
||||||
client: mockDB(t).expectLatestSequenceFilter("user", math.MaxUint64),
|
client: mockDB(t).expectLatestSequenceFilter("user", math.MaxUint64),
|
||||||
|
@@ -61,27 +61,31 @@ func buildQuery(queryFactory *es_models.SearchQueryFactory) (query string, limit
|
|||||||
return query, searchQuery.Limit, values, rowScanner
|
return query, searchQuery.Limit, values, rowScanner
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareCondition(filters []*es_models.Filter) (clause string, values []interface{}) {
|
func prepareCondition(filters [][]*es_models.Filter) (clause string, values []interface{}) {
|
||||||
values = make([]interface{}, len(filters))
|
values = make([]interface{}, 0, len(filters))
|
||||||
clauses := make([]string, len(filters))
|
clauses := make([]string, len(filters))
|
||||||
|
|
||||||
if len(filters) == 0 {
|
if len(filters) == 0 {
|
||||||
return clause, values
|
return clause, values
|
||||||
}
|
}
|
||||||
for i, filter := range filters {
|
for i, filter := range filters {
|
||||||
value := filter.GetValue()
|
subClauses := make([]string, 0, len(filter))
|
||||||
switch value.(type) {
|
for _, f := range filter {
|
||||||
case []bool, []float64, []int64, []string, []es_models.AggregateType, []es_models.EventType, *[]bool, *[]float64, *[]int64, *[]string, *[]es_models.AggregateType, *[]es_models.EventType:
|
value := f.GetValue()
|
||||||
value = pq.Array(value)
|
switch value.(type) {
|
||||||
}
|
case []bool, []float64, []int64, []string, []es_models.AggregateType, []es_models.EventType, *[]bool, *[]float64, *[]int64, *[]string, *[]es_models.AggregateType, *[]es_models.EventType:
|
||||||
|
value = pq.Array(value)
|
||||||
|
}
|
||||||
|
|
||||||
clauses[i] = getCondition(filter)
|
subClauses = append(subClauses, getCondition(f))
|
||||||
if clauses[i] == "" {
|
if subClauses[len(subClauses)-1] == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
|
}
|
||||||
|
values = append(values, value)
|
||||||
}
|
}
|
||||||
values[i] = value
|
clauses[i] = "( " + strings.Join(subClauses, " AND ") + " )"
|
||||||
}
|
}
|
||||||
return " WHERE " + strings.Join(clauses, " AND "), values
|
return " WHERE " + strings.Join(clauses, " OR "), values
|
||||||
}
|
}
|
||||||
|
|
||||||
type scan func(dest ...interface{}) error
|
type scan func(dest ...interface{}) error
|
||||||
@@ -162,8 +166,11 @@ func getCondition(filter *es_models.Filter) (condition string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getConditionFormat(operation es_models.Operation) string {
|
func getConditionFormat(operation es_models.Operation) string {
|
||||||
if operation == es_models.Operation_In {
|
switch operation {
|
||||||
|
case es_models.Operation_In:
|
||||||
return "%s %s ANY(?)"
|
return "%s %s ANY(?)"
|
||||||
|
case es_models.Operation_NotIn:
|
||||||
|
return "%s %s ALL(?)"
|
||||||
}
|
}
|
||||||
return "%s %s ?"
|
return "%s %s ?"
|
||||||
}
|
}
|
||||||
@@ -200,6 +207,8 @@ func getOperation(operation es_models.Operation) string {
|
|||||||
return ">"
|
return ">"
|
||||||
case es_models.Operation_Less:
|
case es_models.Operation_Less:
|
||||||
return "<"
|
return "<"
|
||||||
|
case es_models.Operation_NotIn:
|
||||||
|
return "<>"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@@ -309,7 +309,7 @@ func prepareTestScan(err error, res []interface{}) scan {
|
|||||||
|
|
||||||
func Test_prepareCondition(t *testing.T) {
|
func Test_prepareCondition(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
filters []*es_models.Filter
|
filters [][]*es_models.Filter
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
clause string
|
clause string
|
||||||
@@ -333,7 +333,7 @@ func Test_prepareCondition(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "empty filters",
|
name: "empty filters",
|
||||||
args: args{
|
args: args{
|
||||||
filters: []*es_models.Filter{},
|
filters: [][]*es_models.Filter{},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
clause: "",
|
clause: "",
|
||||||
@@ -343,8 +343,10 @@ func Test_prepareCondition(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "invalid condition",
|
name: "invalid condition",
|
||||||
args: args{
|
args: args{
|
||||||
filters: []*es_models.Filter{
|
filters: [][]*es_models.Filter{
|
||||||
es_models.NewFilter(es_models.Field_AggregateID, "wrong", es_models.Operation(-1)),
|
{
|
||||||
|
es_models.NewFilter(es_models.Field_AggregateID, "wrong", es_models.Operation(-1)),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -355,26 +357,30 @@ func Test_prepareCondition(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "array as condition value",
|
name: "array as condition value",
|
||||||
args: args{
|
args: args{
|
||||||
filters: []*es_models.Filter{
|
filters: [][]*es_models.Filter{
|
||||||
es_models.NewFilter(es_models.Field_AggregateType, []es_models.AggregateType{"user", "org"}, es_models.Operation_In),
|
{
|
||||||
|
es_models.NewFilter(es_models.Field_AggregateType, []es_models.AggregateType{"user", "org"}, es_models.Operation_In),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
clause: " WHERE aggregate_type = ANY(?)",
|
clause: " WHERE ( aggregate_type = ANY(?) )",
|
||||||
values: []interface{}{pq.Array([]es_models.AggregateType{"user", "org"})},
|
values: []interface{}{pq.Array([]es_models.AggregateType{"user", "org"})},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple filters",
|
name: "multiple filters",
|
||||||
args: args{
|
args: args{
|
||||||
filters: []*es_models.Filter{
|
filters: [][]*es_models.Filter{
|
||||||
es_models.NewFilter(es_models.Field_AggregateType, []es_models.AggregateType{"user", "org"}, es_models.Operation_In),
|
{
|
||||||
es_models.NewFilter(es_models.Field_AggregateID, "1234", es_models.Operation_Equals),
|
es_models.NewFilter(es_models.Field_AggregateType, []es_models.AggregateType{"user", "org"}, es_models.Operation_In),
|
||||||
es_models.NewFilter(es_models.Field_EventType, []es_models.EventType{"user.created", "org.created"}, es_models.Operation_In),
|
es_models.NewFilter(es_models.Field_AggregateID, "1234", es_models.Operation_Equals),
|
||||||
|
es_models.NewFilter(es_models.Field_EventType, []es_models.EventType{"user.created", "org.created"}, es_models.Operation_In),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
clause: " WHERE aggregate_type = ANY(?) AND aggregate_id = ? AND event_type = ANY(?)",
|
clause: " WHERE ( aggregate_type = ANY(?) AND aggregate_id = ? AND event_type = ANY(?) )",
|
||||||
values: []interface{}{pq.Array([]es_models.AggregateType{"user", "org"}), "1234", pq.Array([]es_models.EventType{"user.created", "org.created"})},
|
values: []interface{}{pq.Array([]es_models.AggregateType{"user", "org"}), "1234", pq.Array([]es_models.EventType{"user.created", "org.created"})},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -428,10 +434,10 @@ func Test_buildQuery(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "with order by desc",
|
name: "with order by desc",
|
||||||
args: args{
|
args: args{
|
||||||
queryFactory: es_models.NewSearchQueryFactory("user").OrderDesc(),
|
queryFactory: es_models.NewSearchQueryFactory().OrderDesc().AddQuery().AggregateTypes("user").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE aggregate_type = $1 ORDER BY event_sequence DESC",
|
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE ( aggregate_type = $1 ) ORDER BY event_sequence DESC",
|
||||||
rowScanner: true,
|
rowScanner: true,
|
||||||
values: []interface{}{es_models.AggregateType("user")},
|
values: []interface{}{es_models.AggregateType("user")},
|
||||||
},
|
},
|
||||||
@@ -439,10 +445,10 @@ func Test_buildQuery(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "with limit",
|
name: "with limit",
|
||||||
args: args{
|
args: args{
|
||||||
queryFactory: es_models.NewSearchQueryFactory("user").Limit(5),
|
queryFactory: es_models.NewSearchQueryFactory().Limit(5).AddQuery().AggregateTypes("user").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE aggregate_type = $1 ORDER BY event_sequence LIMIT $2",
|
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE ( aggregate_type = $1 ) ORDER BY event_sequence LIMIT $2",
|
||||||
rowScanner: true,
|
rowScanner: true,
|
||||||
values: []interface{}{es_models.AggregateType("user"), uint64(5)},
|
values: []interface{}{es_models.AggregateType("user"), uint64(5)},
|
||||||
limit: 5,
|
limit: 5,
|
||||||
@@ -451,10 +457,10 @@ func Test_buildQuery(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "with limit and order by desc",
|
name: "with limit and order by desc",
|
||||||
args: args{
|
args: args{
|
||||||
queryFactory: es_models.NewSearchQueryFactory("user").Limit(5).OrderDesc(),
|
queryFactory: es_models.NewSearchQueryFactory().Limit(5).OrderDesc().AddQuery().AggregateTypes("user").Factory(),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE aggregate_type = $1 ORDER BY event_sequence DESC LIMIT $2",
|
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE ( aggregate_type = $1 ) ORDER BY event_sequence DESC LIMIT $2",
|
||||||
rowScanner: true,
|
rowScanner: true,
|
||||||
values: []interface{}{es_models.AggregateType("user"), uint64(5)},
|
values: []interface{}{es_models.AggregateType("user"), uint64(5)},
|
||||||
limit: 5,
|
limit: 5,
|
||||||
|
@@ -7,16 +7,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
|
||||||
"github.com/cockroachdb/cockroach-go/v2/crdb"
|
"github.com/cockroachdb/cockroach-go/v2/crdb"
|
||||||
|
|
||||||
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
insertStmtFormat = "INSERT INTO %s" +
|
insertStmtFormat = "INSERT INTO %s" +
|
||||||
" (locker_id, locked_until, view_name) VALUES ($1, now()+$2::INTERVAL, $3)" +
|
" (locker_id, locked_until, view_name, instance_id) VALUES ($1, now()+$2::INTERVAL, $3, $4)" +
|
||||||
" ON CONFLICT (view_name)" +
|
" ON CONFLICT (view_name, instance_id)" +
|
||||||
" DO UPDATE SET locker_id = $4, locked_until = now()+$5::INTERVAL" +
|
" DO UPDATE SET locker_id = $1, locked_until = now()+$2::INTERVAL" +
|
||||||
" WHERE locks.view_name = $6 AND (locks.locker_id = $7 OR locks.locked_until < now())"
|
" WHERE locks.view_name = $3 AND locks.instance_id = $4 AND (locks.locker_id = $1 OR locks.locked_until < now())"
|
||||||
millisecondsAsSeconds = int64(time.Second / time.Millisecond)
|
millisecondsAsSeconds = int64(time.Second / time.Millisecond)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,13 +27,11 @@ type lock struct {
|
|||||||
ViewName string `gorm:"column:view_name;primary_key"`
|
ViewName string `gorm:"column:view_name;primary_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Renew(dbClient *sql.DB, lockTable, lockerID, viewModel string, waitTime time.Duration) error {
|
func Renew(dbClient *sql.DB, lockTable, lockerID, viewModel, instanceID string, waitTime time.Duration) error {
|
||||||
return crdb.ExecuteTx(context.Background(), dbClient, nil, func(tx *sql.Tx) error {
|
return crdb.ExecuteTx(context.Background(), dbClient, nil, func(tx *sql.Tx) error {
|
||||||
insert := fmt.Sprintf(insertStmtFormat, lockTable)
|
insert := fmt.Sprintf(insertStmtFormat, lockTable)
|
||||||
result, err := tx.Exec(insert,
|
result, err := tx.Exec(insert,
|
||||||
lockerID, waitTime.Milliseconds()/millisecondsAsSeconds, viewModel,
|
lockerID, waitTime.Milliseconds()/millisecondsAsSeconds, viewModel, instanceID)
|
||||||
lockerID, waitTime.Milliseconds()/millisecondsAsSeconds,
|
|
||||||
viewModel, lockerID)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
|
@@ -55,10 +55,10 @@ func (db *dbMock) expectReleaseSavepoint() *dbMock {
|
|||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *dbMock) expectRenew(lockerID, view string, affectedRows int64) *dbMock {
|
func (db *dbMock) expectRenew(lockerID, view, instanceID string, affectedRows int64) *dbMock {
|
||||||
query := db.mock.
|
query := db.mock.
|
||||||
ExpectExec(`INSERT INTO table\.locks \(locker_id, locked_until, view_name\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\) ON CONFLICT \(view_name\) DO UPDATE SET locker_id = \$4, locked_until = now\(\)\+\$5::INTERVAL WHERE locks\.view_name = \$6 AND \(locks\.locker_id = \$7 OR locks\.locked_until < now\(\)\)`).
|
ExpectExec(`INSERT INTO table\.locks \(locker_id, locked_until, view_name, instance_id\) VALUES \(\$1, now\(\)\+\$2::INTERVAL, \$3\, \$4\) ON CONFLICT \(view_name, instance_id\) DO UPDATE SET locker_id = \$1, locked_until = now\(\)\+\$2::INTERVAL WHERE locks\.view_name = \$3 AND locks\.instance_id = \$4 AND \(locks\.locker_id = \$1 OR locks\.locked_until < now\(\)\)`).
|
||||||
WithArgs(lockerID, sqlmock.AnyArg(), view, lockerID, sqlmock.AnyArg(), view, lockerID).
|
WithArgs(lockerID, sqlmock.AnyArg(), view, instanceID).
|
||||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
|
||||||
if affectedRows == 0 {
|
if affectedRows == 0 {
|
||||||
@@ -75,10 +75,11 @@ func Test_locker_Renew(t *testing.T) {
|
|||||||
db *dbMock
|
db *dbMock
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
tableName string
|
tableName string
|
||||||
lockerID string
|
lockerID string
|
||||||
viewModel string
|
viewModel string
|
||||||
waitTime time.Duration
|
instanceID string
|
||||||
|
waitTime time.Duration
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -92,11 +93,11 @@ func Test_locker_Renew(t *testing.T) {
|
|||||||
db: mockDB(t).
|
db: mockDB(t).
|
||||||
expectBegin().
|
expectBegin().
|
||||||
expectSavepoint().
|
expectSavepoint().
|
||||||
expectRenew("locker", "view", 1).
|
expectRenew("locker", "view", "instanceID", 1).
|
||||||
expectReleaseSavepoint().
|
expectReleaseSavepoint().
|
||||||
expectCommit(),
|
expectCommit(),
|
||||||
},
|
},
|
||||||
args: args{tableName: "table.locks", lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second},
|
args: args{tableName: "table.locks", lockerID: "locker", viewModel: "view", instanceID: "instanceID", waitTime: 1 * time.Second},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -105,16 +106,16 @@ func Test_locker_Renew(t *testing.T) {
|
|||||||
db: mockDB(t).
|
db: mockDB(t).
|
||||||
expectBegin().
|
expectBegin().
|
||||||
expectSavepoint().
|
expectSavepoint().
|
||||||
expectRenew("locker", "view", 0).
|
expectRenew("locker", "view", "instanceID", 0).
|
||||||
expectRollback(),
|
expectRollback(),
|
||||||
},
|
},
|
||||||
args: args{tableName: "table.locks", lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second},
|
args: args{tableName: "table.locks", lockerID: "locker", viewModel: "view", instanceID: "instanceID", waitTime: 1 * time.Second},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := Renew(tt.fields.db.db, tt.args.tableName, tt.args.lockerID, tt.args.viewModel, tt.args.waitTime); (err != nil) != tt.wantErr {
|
if err := Renew(tt.fields.db.db, tt.args.tableName, tt.args.lockerID, tt.args.viewModel, tt.args.instanceID, tt.args.waitTime); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("locker.Renew() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("locker.Renew() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
if err := tt.fields.db.mock.ExpectationsWereMet(); err != nil {
|
if err := tt.fields.db.mock.ExpectationsWereMet(); err != nil {
|
||||||
|
@@ -1,56 +1,42 @@
|
|||||||
// Code generated by MockGen. DO NOT EDIT.
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
// Source: github.com/caos/zitadel/internal/eventstore (interfaces: Eventstore)
|
// Source: github.com/caos/zitadel/internal/eventstore/v1 (interfaces: Eventstore)
|
||||||
|
|
||||||
// Package mock is a generated GoMock package.
|
// Package mock is a generated GoMock package.
|
||||||
package mock
|
package mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
reflect "reflect"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
|
||||||
|
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||||
models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
models "github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
reflect "reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockEventstore is a mock of Eventstore interface
|
// MockEventstore is a mock of Eventstore interface.
|
||||||
type MockEventstore struct {
|
type MockEventstore struct {
|
||||||
ctrl *gomock.Controller
|
ctrl *gomock.Controller
|
||||||
recorder *MockEventstoreMockRecorder
|
recorder *MockEventstoreMockRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// MockEventstoreMockRecorder is the mock recorder for MockEventstore
|
// MockEventstoreMockRecorder is the mock recorder for MockEventstore.
|
||||||
type MockEventstoreMockRecorder struct {
|
type MockEventstoreMockRecorder struct {
|
||||||
mock *MockEventstore
|
mock *MockEventstore
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMockEventstore creates a new mock instance
|
// NewMockEventstore creates a new mock instance.
|
||||||
func NewMockEventstore(ctrl *gomock.Controller) *MockEventstore {
|
func NewMockEventstore(ctrl *gomock.Controller) *MockEventstore {
|
||||||
mock := &MockEventstore{ctrl: ctrl}
|
mock := &MockEventstore{ctrl: ctrl}
|
||||||
mock.recorder = &MockEventstoreMockRecorder{mock}
|
mock.recorder = &MockEventstoreMockRecorder{mock}
|
||||||
return mock
|
return mock
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
func (m *MockEventstore) EXPECT() *MockEventstoreMockRecorder {
|
func (m *MockEventstore) EXPECT() *MockEventstoreMockRecorder {
|
||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// AggregateCreator mocks base method
|
// FilterEvents mocks base method.
|
||||||
func (m *MockEventstore) AggregateCreator() *models.AggregateCreator {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "AggregateCreator")
|
|
||||||
ret0, _ := ret[0].(*models.AggregateCreator)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// AggregateCreator indicates an expected call of AggregateCreator
|
|
||||||
func (mr *MockEventstoreMockRecorder) AggregateCreator() *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AggregateCreator", reflect.TypeOf((*MockEventstore)(nil).AggregateCreator))
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilterEvents mocks base method
|
|
||||||
func (m *MockEventstore) FilterEvents(arg0 context.Context, arg1 *models.SearchQuery) ([]*models.Event, error) {
|
func (m *MockEventstore) FilterEvents(arg0 context.Context, arg1 *models.SearchQuery) ([]*models.Event, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "FilterEvents", arg0, arg1)
|
ret := m.ctrl.Call(m, "FilterEvents", arg0, arg1)
|
||||||
@@ -59,13 +45,13 @@ func (m *MockEventstore) FilterEvents(arg0 context.Context, arg1 *models.SearchQ
|
|||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterEvents indicates an expected call of FilterEvents
|
// FilterEvents indicates an expected call of FilterEvents.
|
||||||
func (mr *MockEventstoreMockRecorder) FilterEvents(arg0, arg1 interface{}) *gomock.Call {
|
func (mr *MockEventstoreMockRecorder) FilterEvents(arg0, arg1 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterEvents", reflect.TypeOf((*MockEventstore)(nil).FilterEvents), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterEvents", reflect.TypeOf((*MockEventstore)(nil).FilterEvents), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Health mocks base method
|
// Health mocks base method.
|
||||||
func (m *MockEventstore) Health(arg0 context.Context) error {
|
func (m *MockEventstore) Health(arg0 context.Context) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "Health", arg0)
|
ret := m.ctrl.Call(m, "Health", arg0)
|
||||||
@@ -73,47 +59,13 @@ func (m *MockEventstore) Health(arg0 context.Context) error {
|
|||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Health indicates an expected call of Health
|
// Health indicates an expected call of Health.
|
||||||
func (mr *MockEventstoreMockRecorder) Health(arg0 interface{}) *gomock.Call {
|
func (mr *MockEventstoreMockRecorder) Health(arg0 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockEventstore)(nil).Health), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockEventstore)(nil).Health), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LatestSequence mocks base method
|
// Subscribe mocks base method.
|
||||||
func (m *MockEventstore) LatestSequence(arg0 context.Context, arg1 *models.SearchQueryFactory) (uint64, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "LatestSequence", arg0, arg1)
|
|
||||||
ret0, _ := ret[0].(uint64)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// LatestSequence indicates an expected call of LatestSequence
|
|
||||||
func (mr *MockEventstoreMockRecorder) LatestSequence(arg0, arg1 interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LatestSequence", reflect.TypeOf((*MockEventstore)(nil).LatestSequence), arg0, arg1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PushAggregates mocks base method
|
|
||||||
func (m *MockEventstore) PushAggregates(arg0 context.Context, arg1 ...*models.Aggregate) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
varargs := []interface{}{arg0}
|
|
||||||
for _, a := range arg1 {
|
|
||||||
varargs = append(varargs, a)
|
|
||||||
}
|
|
||||||
ret := m.ctrl.Call(m, "PushAggregates", varargs...)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// PushAggregates indicates an expected call of PushAggregates
|
|
||||||
func (mr *MockEventstoreMockRecorder) PushAggregates(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
varargs := append([]interface{}{arg0}, arg1...)
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushAggregates", reflect.TypeOf((*MockEventstore)(nil).PushAggregates), varargs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscribe mocks base method
|
|
||||||
func (m *MockEventstore) Subscribe(arg0 ...models.AggregateType) *v1.Subscription {
|
func (m *MockEventstore) Subscribe(arg0 ...models.AggregateType) *v1.Subscription {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
varargs := []interface{}{}
|
varargs := []interface{}{}
|
||||||
@@ -125,22 +77,8 @@ func (m *MockEventstore) Subscribe(arg0 ...models.AggregateType) *v1.Subscriptio
|
|||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe indicates an expected call of Subscribe
|
// Subscribe indicates an expected call of Subscribe.
|
||||||
func (mr *MockEventstoreMockRecorder) Subscribe(arg0 ...interface{}) *gomock.Call {
|
func (mr *MockEventstoreMockRecorder) Subscribe(arg0 ...interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockEventstore)(nil).Subscribe), arg0...)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockEventstore)(nil).Subscribe), arg0...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// V2 mocks base method
|
|
||||||
func (m *MockEventstore) V2() *eventstore.Eventstore {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "V2")
|
|
||||||
ret0, _ := ret[0].(*eventstore.Eventstore)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// V2 indicates an expected call of V2
|
|
||||||
func (mr *MockEventstoreMockRecorder) V2() *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "V2", reflect.TypeOf((*MockEventstore)(nil).V2))
|
|
||||||
}
|
|
||||||
|
@@ -190,7 +190,7 @@ func TestAggregate_Validate(t *testing.T) {
|
|||||||
resourceOwner: "org",
|
resourceOwner: "org",
|
||||||
PreviousSequence: 5,
|
PreviousSequence: 5,
|
||||||
Precondition: &precondition{
|
Precondition: &precondition{
|
||||||
Query: NewSearchQuery().AggregateIDFilter("hodor"),
|
Query: NewSearchQuery().AddQuery().AggregateIDFilter("hodor").SearchQuery(),
|
||||||
},
|
},
|
||||||
Events: []*Event{
|
Events: []*Event{
|
||||||
{
|
{
|
||||||
@@ -240,7 +240,7 @@ func TestAggregate_Validate(t *testing.T) {
|
|||||||
PreviousSequence: 5,
|
PreviousSequence: 5,
|
||||||
Precondition: &precondition{
|
Precondition: &precondition{
|
||||||
Validation: func(...*Event) error { return nil },
|
Validation: func(...*Event) error { return nil },
|
||||||
Query: NewSearchQuery().AggregateIDFilter("hodor"),
|
Query: NewSearchQuery().AddQuery().AggregateIDFilter("hodor").SearchQuery(),
|
||||||
},
|
},
|
||||||
Events: []*Event{
|
Events: []*Event{
|
||||||
{
|
{
|
||||||
|
@@ -7,4 +7,5 @@ const (
|
|||||||
Operation_Greater
|
Operation_Greater
|
||||||
Operation_Less
|
Operation_Less
|
||||||
Operation_In
|
Operation_In
|
||||||
|
Operation_NotIn
|
||||||
)
|
)
|
||||||
|
@@ -9,24 +9,31 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SearchQueryFactory struct {
|
type SearchQueryFactory struct {
|
||||||
columns Columns
|
columns Columns
|
||||||
limit uint64
|
limit uint64
|
||||||
desc bool
|
desc bool
|
||||||
aggregateTypes []AggregateType
|
queries []*query
|
||||||
aggregateIDs []string
|
}
|
||||||
sequenceFrom uint64
|
|
||||||
sequenceTo uint64
|
type query struct {
|
||||||
eventTypes []EventType
|
desc bool
|
||||||
resourceOwner string
|
aggregateTypes []AggregateType
|
||||||
instanceID string
|
aggregateIDs []string
|
||||||
creationDate time.Time
|
sequenceFrom uint64
|
||||||
|
sequenceTo uint64
|
||||||
|
eventTypes []EventType
|
||||||
|
resourceOwner string
|
||||||
|
instanceID string
|
||||||
|
ignoredInstanceIDs []string
|
||||||
|
creationDate time.Time
|
||||||
|
factory *SearchQueryFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchQuery struct {
|
type searchQuery struct {
|
||||||
Columns Columns
|
Columns Columns
|
||||||
Limit uint64
|
Limit uint64
|
||||||
Desc bool
|
Desc bool
|
||||||
Filters []*Filter
|
Filters [][]*Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
type Columns int32
|
type Columns int32
|
||||||
@@ -39,49 +46,55 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
//FactoryFromSearchQuery is deprecated because it's for migration purposes. use NewSearchQueryFactory
|
//FactoryFromSearchQuery is deprecated because it's for migration purposes. use NewSearchQueryFactory
|
||||||
func FactoryFromSearchQuery(query *SearchQuery) *SearchQueryFactory {
|
func FactoryFromSearchQuery(q *SearchQuery) *SearchQueryFactory {
|
||||||
factory := &SearchQueryFactory{
|
factory := &SearchQueryFactory{
|
||||||
columns: Columns_Event,
|
columns: Columns_Event,
|
||||||
desc: query.Desc,
|
desc: q.Desc,
|
||||||
limit: query.Limit,
|
limit: q.Limit,
|
||||||
|
queries: make([]*query, len(q.Queries)),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filter := range query.Filters {
|
for i, qq := range q.Queries {
|
||||||
switch filter.field {
|
factory.queries[i] = &query{factory: factory}
|
||||||
case Field_AggregateType:
|
for _, filter := range qq.Filters {
|
||||||
factory = factory.aggregateTypesMig(filter.value.([]AggregateType)...)
|
switch filter.field {
|
||||||
case Field_AggregateID:
|
case Field_AggregateType:
|
||||||
if aggregateID, ok := filter.value.(string); ok {
|
factory.queries[i] = factory.queries[i].aggregateTypesMig(filter.value.([]AggregateType)...)
|
||||||
factory = factory.AggregateIDs(aggregateID)
|
case Field_AggregateID:
|
||||||
} else if aggregateIDs, ok := filter.value.([]string); ok {
|
if aggregateID, ok := filter.value.(string); ok {
|
||||||
factory = factory.AggregateIDs(aggregateIDs...)
|
factory.queries[i] = factory.queries[i].AggregateIDs(aggregateID)
|
||||||
|
} else if aggregateIDs, ok := filter.value.([]string); ok {
|
||||||
|
factory.queries[i] = factory.queries[i].AggregateIDs(aggregateIDs...)
|
||||||
|
}
|
||||||
|
case Field_LatestSequence:
|
||||||
|
if filter.operation == Operation_Greater {
|
||||||
|
factory.queries[i] = factory.queries[i].SequenceGreater(filter.value.(uint64))
|
||||||
|
} else {
|
||||||
|
factory.queries[i] = factory.queries[i].SequenceLess(filter.value.(uint64))
|
||||||
|
}
|
||||||
|
case Field_ResourceOwner:
|
||||||
|
factory.queries[i] = factory.queries[i].ResourceOwner(filter.value.(string))
|
||||||
|
case Field_InstanceID:
|
||||||
|
if filter.operation == Operation_Equals {
|
||||||
|
factory.queries[i] = factory.queries[i].InstanceID(filter.value.(string))
|
||||||
|
} else if filter.operation == Operation_NotIn {
|
||||||
|
factory.queries[i] = factory.queries[i].IgnoredInstanceIDs(filter.value.([]string)...)
|
||||||
|
}
|
||||||
|
case Field_EventType:
|
||||||
|
factory.queries[i] = factory.queries[i].EventTypes(filter.value.([]EventType)...)
|
||||||
|
case Field_EditorService, Field_EditorUser:
|
||||||
|
logging.WithFields("value", filter.value).Panic("field not converted to factory")
|
||||||
|
case Field_CreationDate:
|
||||||
|
factory.queries[i] = factory.queries[i].CreationDateNewer(filter.value.(time.Time))
|
||||||
}
|
}
|
||||||
case Field_LatestSequence:
|
|
||||||
if filter.operation == Operation_Greater {
|
|
||||||
factory = factory.SequenceGreater(filter.value.(uint64))
|
|
||||||
} else {
|
|
||||||
factory = factory.SequenceLess(filter.value.(uint64))
|
|
||||||
}
|
|
||||||
case Field_ResourceOwner:
|
|
||||||
factory = factory.ResourceOwner(filter.value.(string))
|
|
||||||
case Field_InstanceID:
|
|
||||||
factory = factory.InstanceID(filter.value.(string))
|
|
||||||
case Field_EventType:
|
|
||||||
factory = factory.EventTypes(filter.value.([]EventType)...)
|
|
||||||
case Field_EditorService, Field_EditorUser:
|
|
||||||
logging.Log("MODEL-Mr0VN").WithField("value", filter.value).Panic("field not converted to factory")
|
|
||||||
case Field_CreationDate:
|
|
||||||
factory = factory.CreationDateNewer(filter.value.(time.Time))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return factory
|
return factory
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSearchQueryFactory(aggregateTypes ...AggregateType) *SearchQueryFactory {
|
func NewSearchQueryFactory() *SearchQueryFactory {
|
||||||
return &SearchQueryFactory{
|
return &SearchQueryFactory{}
|
||||||
aggregateTypes: aggregateTypes,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) Columns(columns Columns) *SearchQueryFactory {
|
func (factory *SearchQueryFactory) Columns(columns Columns) *SearchQueryFactory {
|
||||||
@@ -94,46 +107,6 @@ func (factory *SearchQueryFactory) Limit(limit uint64) *SearchQueryFactory {
|
|||||||
return factory
|
return factory
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) SequenceGreater(sequence uint64) *SearchQueryFactory {
|
|
||||||
factory.sequenceFrom = sequence
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) SequenceLess(sequence uint64) *SearchQueryFactory {
|
|
||||||
factory.sequenceTo = sequence
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) AggregateIDs(ids ...string) *SearchQueryFactory {
|
|
||||||
factory.aggregateIDs = ids
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) aggregateTypesMig(types ...AggregateType) *SearchQueryFactory {
|
|
||||||
factory.aggregateTypes = types
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) EventTypes(types ...EventType) *SearchQueryFactory {
|
|
||||||
factory.eventTypes = types
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) ResourceOwner(resourceOwner string) *SearchQueryFactory {
|
|
||||||
factory.resourceOwner = resourceOwner
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) InstanceID(instanceID string) *SearchQueryFactory {
|
|
||||||
factory.instanceID = instanceID
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) CreationDateNewer(time time.Time) *SearchQueryFactory {
|
|
||||||
factory.creationDate = time
|
|
||||||
return factory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) OrderDesc() *SearchQueryFactory {
|
func (factory *SearchQueryFactory) OrderDesc() *SearchQueryFactory {
|
||||||
factory.desc = true
|
factory.desc = true
|
||||||
return factory
|
return factory
|
||||||
@@ -144,27 +117,89 @@ func (factory *SearchQueryFactory) OrderAsc() *SearchQueryFactory {
|
|||||||
return factory
|
return factory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (factory *SearchQueryFactory) AddQuery() *query {
|
||||||
|
q := &query{factory: factory}
|
||||||
|
factory.queries = append(factory.queries, q)
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) Factory() *SearchQueryFactory {
|
||||||
|
return q.factory
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) SequenceGreater(sequence uint64) *query {
|
||||||
|
q.sequenceFrom = sequence
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) SequenceLess(sequence uint64) *query {
|
||||||
|
q.sequenceTo = sequence
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) AggregateTypes(types ...AggregateType) *query {
|
||||||
|
q.aggregateTypes = types
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) AggregateIDs(ids ...string) *query {
|
||||||
|
q.aggregateIDs = ids
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) aggregateTypesMig(types ...AggregateType) *query {
|
||||||
|
q.aggregateTypes = types
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) EventTypes(types ...EventType) *query {
|
||||||
|
q.eventTypes = types
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) ResourceOwner(resourceOwner string) *query {
|
||||||
|
q.resourceOwner = resourceOwner
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) InstanceID(instanceID string) *query {
|
||||||
|
q.instanceID = instanceID
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) IgnoredInstanceIDs(instanceIDs ...string) *query {
|
||||||
|
q.ignoredInstanceIDs = instanceIDs
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) CreationDateNewer(time time.Time) *query {
|
||||||
|
q.creationDate = time
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) Build() (*searchQuery, error) {
|
func (factory *SearchQueryFactory) Build() (*searchQuery, error) {
|
||||||
if factory == nil ||
|
if factory == nil ||
|
||||||
len(factory.aggregateTypes) < 1 ||
|
len(factory.queries) < 1 ||
|
||||||
(factory.columns < 0 || factory.columns >= columnsCount) {
|
(factory.columns < 0 || factory.columns >= columnsCount) {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-tGAD3", "factory invalid")
|
return nil, errors.ThrowPreconditionFailed(nil, "MODEL-tGAD3", "factory invalid")
|
||||||
}
|
}
|
||||||
filters := []*Filter{
|
filters := make([][]*Filter, len(factory.queries))
|
||||||
factory.aggregateTypeFilter(),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range []func() *Filter{
|
for i, query := range factory.queries {
|
||||||
factory.aggregateIDFilter,
|
for _, f := range []func() *Filter{
|
||||||
factory.sequenceFromFilter,
|
query.aggregateTypeFilter,
|
||||||
factory.sequenceToFilter,
|
query.aggregateIDFilter,
|
||||||
factory.eventTypeFilter,
|
query.sequenceFromFilter,
|
||||||
factory.resourceOwnerFilter,
|
query.sequenceToFilter,
|
||||||
factory.instanceIDFilter,
|
query.eventTypeFilter,
|
||||||
factory.creationDateNewerFilter,
|
query.resourceOwnerFilter,
|
||||||
} {
|
query.instanceIDFilter,
|
||||||
if filter := f(); filter != nil {
|
query.ignoredInstanceIDsFilter,
|
||||||
filters = append(filters, filter)
|
query.creationDateNewerFilter,
|
||||||
|
} {
|
||||||
|
if filter := f(); filter != nil {
|
||||||
|
filters[i] = append(filters[i], filter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,72 +211,79 @@ func (factory *SearchQueryFactory) Build() (*searchQuery, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) aggregateIDFilter() *Filter {
|
func (q *query) aggregateIDFilter() *Filter {
|
||||||
if len(factory.aggregateIDs) < 1 {
|
if len(q.aggregateIDs) < 1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(factory.aggregateIDs) == 1 {
|
if len(q.aggregateIDs) == 1 {
|
||||||
return NewFilter(Field_AggregateID, factory.aggregateIDs[0], Operation_Equals)
|
return NewFilter(Field_AggregateID, q.aggregateIDs[0], Operation_Equals)
|
||||||
}
|
}
|
||||||
return NewFilter(Field_AggregateID, factory.aggregateIDs, Operation_In)
|
return NewFilter(Field_AggregateID, q.aggregateIDs, Operation_In)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) eventTypeFilter() *Filter {
|
func (q *query) eventTypeFilter() *Filter {
|
||||||
if len(factory.eventTypes) < 1 {
|
if len(q.eventTypes) < 1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(factory.eventTypes) == 1 {
|
if len(q.eventTypes) == 1 {
|
||||||
return NewFilter(Field_EventType, factory.eventTypes[0], Operation_Equals)
|
return NewFilter(Field_EventType, q.eventTypes[0], Operation_Equals)
|
||||||
}
|
}
|
||||||
return NewFilter(Field_EventType, factory.eventTypes, Operation_In)
|
return NewFilter(Field_EventType, q.eventTypes, Operation_In)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) aggregateTypeFilter() *Filter {
|
func (q *query) aggregateTypeFilter() *Filter {
|
||||||
if len(factory.aggregateTypes) == 1 {
|
if len(q.aggregateTypes) == 1 {
|
||||||
return NewFilter(Field_AggregateType, factory.aggregateTypes[0], Operation_Equals)
|
return NewFilter(Field_AggregateType, q.aggregateTypes[0], Operation_Equals)
|
||||||
}
|
}
|
||||||
return NewFilter(Field_AggregateType, factory.aggregateTypes, Operation_In)
|
return NewFilter(Field_AggregateType, q.aggregateTypes, Operation_In)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) sequenceFromFilter() *Filter {
|
func (q *query) sequenceFromFilter() *Filter {
|
||||||
if factory.sequenceFrom == 0 {
|
if q.sequenceFrom == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sortOrder := Operation_Greater
|
sortOrder := Operation_Greater
|
||||||
if factory.desc {
|
if q.factory.desc {
|
||||||
sortOrder = Operation_Less
|
sortOrder = Operation_Less
|
||||||
}
|
}
|
||||||
return NewFilter(Field_LatestSequence, factory.sequenceFrom, sortOrder)
|
return NewFilter(Field_LatestSequence, q.sequenceFrom, sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) sequenceToFilter() *Filter {
|
func (q *query) sequenceToFilter() *Filter {
|
||||||
if factory.sequenceTo == 0 {
|
if q.sequenceTo == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sortOrder := Operation_Less
|
sortOrder := Operation_Less
|
||||||
if factory.desc {
|
if q.factory.desc {
|
||||||
sortOrder = Operation_Greater
|
sortOrder = Operation_Greater
|
||||||
}
|
}
|
||||||
return NewFilter(Field_LatestSequence, factory.sequenceTo, sortOrder)
|
return NewFilter(Field_LatestSequence, q.sequenceTo, sortOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) resourceOwnerFilter() *Filter {
|
func (q *query) resourceOwnerFilter() *Filter {
|
||||||
if factory.resourceOwner == "" {
|
if q.resourceOwner == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return NewFilter(Field_ResourceOwner, factory.resourceOwner, Operation_Equals)
|
return NewFilter(Field_ResourceOwner, q.resourceOwner, Operation_Equals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) instanceIDFilter() *Filter {
|
func (q *query) instanceIDFilter() *Filter {
|
||||||
if factory.instanceID == "" {
|
if q.instanceID == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return NewFilter(Field_InstanceID, factory.instanceID, Operation_Equals)
|
return NewFilter(Field_InstanceID, q.instanceID, Operation_Equals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *SearchQueryFactory) creationDateNewerFilter() *Filter {
|
func (q *query) ignoredInstanceIDsFilter() *Filter {
|
||||||
if factory.creationDate.IsZero() {
|
if len(q.ignoredInstanceIDs) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return NewFilter(Field_CreationDate, factory.creationDate, Operation_Greater)
|
return NewFilter(Field_InstanceID, q.ignoredInstanceIDs, Operation_NotIn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *query) creationDateNewerFilter() *Filter {
|
||||||
|
if q.creationDate.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return NewFilter(Field_CreationDate, q.creationDate, Operation_Greater)
|
||||||
}
|
}
|
||||||
|
@@ -11,15 +11,46 @@ type SearchQuery struct {
|
|||||||
Limit uint64
|
Limit uint64
|
||||||
Desc bool
|
Desc bool
|
||||||
Filters []*Filter
|
Filters []*Filter
|
||||||
|
Queries []*Query
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
searchQuery *SearchQuery
|
||||||
|
Filters []*Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewSearchQuery is deprecated. Use SearchQueryFactory
|
//NewSearchQuery is deprecated. Use SearchQueryFactory
|
||||||
func NewSearchQuery() *SearchQuery {
|
func NewSearchQuery() *SearchQuery {
|
||||||
return &SearchQuery{
|
return &SearchQuery{
|
||||||
Filters: make([]*Filter, 0, 4),
|
Filters: make([]*Filter, 0, 4),
|
||||||
|
Queries: make([]*Query, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *SearchQuery) AddQuery() *Query {
|
||||||
|
query := &Query{
|
||||||
|
searchQuery: q,
|
||||||
|
}
|
||||||
|
q.Queries = append(q.Queries, query)
|
||||||
|
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
//SearchQuery returns the SearchQuery of the sub query
|
||||||
|
func (q *Query) SearchQuery() *SearchQuery {
|
||||||
|
return q.searchQuery
|
||||||
|
}
|
||||||
|
func (q *Query) setFilter(filter *Filter) *Query {
|
||||||
|
for i, f := range q.Filters {
|
||||||
|
if f.field == filter.field && f.field != Field_LatestSequence {
|
||||||
|
q.Filters[i] = filter
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q.Filters = append(q.Filters, filter)
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) SetLimit(limit uint64) *SearchQuery {
|
func (q *SearchQuery) SetLimit(limit uint64) *SearchQuery {
|
||||||
q.Limit = limit
|
q.Limit = limit
|
||||||
return q
|
return q
|
||||||
@@ -35,23 +66,23 @@ func (q *SearchQuery) OrderAsc() *SearchQuery {
|
|||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) AggregateIDFilter(id string) *SearchQuery {
|
func (q *Query) AggregateIDFilter(id string) *Query {
|
||||||
return q.setFilter(NewFilter(Field_AggregateID, id, Operation_Equals))
|
return q.setFilter(NewFilter(Field_AggregateID, id, Operation_Equals))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) AggregateIDsFilter(ids ...string) *SearchQuery {
|
func (q *Query) AggregateIDsFilter(ids ...string) *Query {
|
||||||
return q.setFilter(NewFilter(Field_AggregateID, ids, Operation_In))
|
return q.setFilter(NewFilter(Field_AggregateID, ids, Operation_In))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) AggregateTypeFilter(types ...AggregateType) *SearchQuery {
|
func (q *Query) AggregateTypeFilter(types ...AggregateType) *Query {
|
||||||
return q.setFilter(NewFilter(Field_AggregateType, types, Operation_In))
|
return q.setFilter(NewFilter(Field_AggregateType, types, Operation_In))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) EventTypesFilter(types ...EventType) *SearchQuery {
|
func (q *Query) EventTypesFilter(types ...EventType) *Query {
|
||||||
return q.setFilter(NewFilter(Field_EventType, types, Operation_In))
|
return q.setFilter(NewFilter(Field_EventType, types, Operation_In))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) LatestSequenceFilter(sequence uint64) *SearchQuery {
|
func (q *Query) LatestSequenceFilter(sequence uint64) *Query {
|
||||||
if sequence == 0 {
|
if sequence == 0 {
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
@@ -59,21 +90,25 @@ func (q *SearchQuery) LatestSequenceFilter(sequence uint64) *SearchQuery {
|
|||||||
return q.setFilter(NewFilter(Field_LatestSequence, sequence, sortOrder))
|
return q.setFilter(NewFilter(Field_LatestSequence, sequence, sortOrder))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) SequenceBetween(from, to uint64) *SearchQuery {
|
func (q *Query) SequenceBetween(from, to uint64) *Query {
|
||||||
q.setFilter(NewFilter(Field_LatestSequence, from, Operation_Greater))
|
q.setFilter(NewFilter(Field_LatestSequence, from, Operation_Greater))
|
||||||
q.setFilter(NewFilter(Field_LatestSequence, to, Operation_Less))
|
q.setFilter(NewFilter(Field_LatestSequence, to, Operation_Less))
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) ResourceOwnerFilter(resourceOwner string) *SearchQuery {
|
func (q *Query) ResourceOwnerFilter(resourceOwner string) *Query {
|
||||||
return q.setFilter(NewFilter(Field_ResourceOwner, resourceOwner, Operation_Equals))
|
return q.setFilter(NewFilter(Field_ResourceOwner, resourceOwner, Operation_Equals))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) InstanceIDFilter(instanceID string) *SearchQuery {
|
func (q *Query) InstanceIDFilter(instanceID string) *Query {
|
||||||
return q.setFilter(NewFilter(Field_InstanceID, instanceID, Operation_Equals))
|
return q.setFilter(NewFilter(Field_InstanceID, instanceID, Operation_Equals))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *SearchQuery) CreationDateNewerFilter(time time.Time) *SearchQuery {
|
func (q *Query) ExcludedInstanceIDsFilter(instanceIDs ...string) *Query {
|
||||||
|
return q.setFilter(NewFilter(Field_InstanceID, instanceIDs, Operation_NotIn))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Query) CreationDateNewerFilter(time time.Time) *Query {
|
||||||
return q.setFilter(NewFilter(Field_CreationDate, time, Operation_Greater))
|
return q.setFilter(NewFilter(Field_CreationDate, time, Operation_Greater))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,12 +127,14 @@ func (q *SearchQuery) Validate() error {
|
|||||||
if q == nil {
|
if q == nil {
|
||||||
return errors.ThrowPreconditionFailed(nil, "MODEL-J5xQi", "search query is nil")
|
return errors.ThrowPreconditionFailed(nil, "MODEL-J5xQi", "search query is nil")
|
||||||
}
|
}
|
||||||
if len(q.Filters) == 0 {
|
if len(q.Queries) == 0 {
|
||||||
return errors.ThrowPreconditionFailed(nil, "MODEL-pF3DR", "no filters set")
|
return errors.ThrowPreconditionFailed(nil, "MODEL-pF3DR", "no filters set")
|
||||||
}
|
}
|
||||||
for _, filter := range q.Filters {
|
for _, query := range q.Queries {
|
||||||
if err := filter.Validate(); err != nil {
|
for _, filter := range query.Filters {
|
||||||
return err
|
if err := filter.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,31 +21,48 @@ func testSetLimit(limit uint64) func(factory *SearchQueryFactory) *SearchQueryFa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetSequence(sequence uint64) func(factory *SearchQueryFactory) *SearchQueryFactory {
|
func testAddQuery(queryFuncs ...func(*query) *query) func(*SearchQueryFactory) *SearchQueryFactory {
|
||||||
return func(factory *SearchQueryFactory) *SearchQueryFactory {
|
return func(builder *SearchQueryFactory) *SearchQueryFactory {
|
||||||
factory = factory.SequenceGreater(sequence)
|
query := builder.AddQuery()
|
||||||
return factory
|
for _, queryFunc := range queryFuncs {
|
||||||
|
queryFunc(query)
|
||||||
|
}
|
||||||
|
return query.Factory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetAggregateIDs(aggregateIDs ...string) func(factory *SearchQueryFactory) *SearchQueryFactory {
|
func testSetSequence(sequence uint64) func(*query) *query {
|
||||||
return func(factory *SearchQueryFactory) *SearchQueryFactory {
|
return func(q *query) *query {
|
||||||
factory = factory.AggregateIDs(aggregateIDs...)
|
q.SequenceGreater(sequence)
|
||||||
return factory
|
return q
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetEventTypes(eventTypes ...EventType) func(factory *SearchQueryFactory) *SearchQueryFactory {
|
func testSetAggregateIDs(aggregateIDs ...string) func(*query) *query {
|
||||||
return func(factory *SearchQueryFactory) *SearchQueryFactory {
|
return func(q *query) *query {
|
||||||
factory = factory.EventTypes(eventTypes...)
|
q.AggregateIDs(aggregateIDs...)
|
||||||
return factory
|
return q
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetResourceOwner(resourceOwner string) func(factory *SearchQueryFactory) *SearchQueryFactory {
|
func testSetAggregateTypes(aggregateTypes ...AggregateType) func(*query) *query {
|
||||||
return func(factory *SearchQueryFactory) *SearchQueryFactory {
|
return func(q *query) *query {
|
||||||
factory = factory.ResourceOwner(resourceOwner)
|
q.AggregateTypes(aggregateTypes...)
|
||||||
return factory
|
return q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSetEventTypes(eventTypes ...EventType) func(*query) *query {
|
||||||
|
return func(q *query) *query {
|
||||||
|
q.EventTypes(eventTypes...)
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSetResourceOwner(resourceOwner string) func(*query) *query {
|
||||||
|
return func(q *query) *query {
|
||||||
|
q.ResourceOwner(resourceOwner)
|
||||||
|
return q
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,10 +77,50 @@ func testSetSortOrder(asc bool) func(factory *SearchQueryFactory) *SearchQueryFa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertFactory(t *testing.T, want, got *SearchQueryFactory) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if got.columns != want.columns {
|
||||||
|
t.Errorf("wrong column: got: %v want: %v", got.columns, want.columns)
|
||||||
|
}
|
||||||
|
if got.desc != want.desc {
|
||||||
|
t.Errorf("wrong desc: got: %v want: %v", got.desc, want.desc)
|
||||||
|
}
|
||||||
|
if got.limit != want.limit {
|
||||||
|
t.Errorf("wrong limit: got: %v want: %v", got.limit, want.limit)
|
||||||
|
}
|
||||||
|
if len(got.queries) != len(want.queries) {
|
||||||
|
t.Errorf("wrong length of queries: got: %v want: %v", len(got.queries), len(want.queries))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, query := range got.queries {
|
||||||
|
assertQuery(t, i, want.queries[i], query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertQuery(t *testing.T, i int, want, got *query) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got.aggregateIDs, want.aggregateIDs) {
|
||||||
|
t.Errorf("wrong aggregateIDs in query %d : got: %v want: %v", i, got.aggregateIDs, want.aggregateIDs)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got.aggregateTypes, want.aggregateTypes) {
|
||||||
|
t.Errorf("wrong aggregateTypes in query %d : got: %v want: %v", i, got.aggregateTypes, want.aggregateTypes)
|
||||||
|
}
|
||||||
|
if got.sequenceFrom != want.sequenceFrom {
|
||||||
|
t.Errorf("wrong sequenceFrom in query %d : got: %v want: %v", i, got.sequenceFrom, want.sequenceFrom)
|
||||||
|
}
|
||||||
|
if got.sequenceTo != want.sequenceTo {
|
||||||
|
t.Errorf("wrong sequenceTo in query %d : got: %v want: %v", i, got.sequenceTo, want.sequenceTo)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got.eventTypes, want.eventTypes) {
|
||||||
|
t.Errorf("wrong eventTypes in query %d : got: %v want: %v", i, got.eventTypes, want.eventTypes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSearchQueryFactorySetters(t *testing.T) {
|
func TestSearchQueryFactorySetters(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
aggregateTypes []AggregateType
|
setters []func(*SearchQueryFactory) *SearchQueryFactory
|
||||||
setters []func(*SearchQueryFactory) *SearchQueryFactory
|
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -73,11 +130,9 @@ func TestSearchQueryFactorySetters(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "New factory",
|
name: "New factory",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user", "org"},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{},
|
||||||
},
|
|
||||||
res: &SearchQueryFactory{
|
|
||||||
aggregateTypes: []AggregateType{"user", "org"},
|
|
||||||
},
|
},
|
||||||
|
res: &SearchQueryFactory{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "set columns",
|
name: "set columns",
|
||||||
@@ -100,69 +155,98 @@ func TestSearchQueryFactorySetters(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "set sequence",
|
name: "set sequence",
|
||||||
args: args{
|
args: args{
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testSetSequence(90)},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testAddQuery(testSetSequence(90))},
|
||||||
},
|
},
|
||||||
res: &SearchQueryFactory{
|
res: &SearchQueryFactory{
|
||||||
sequenceFrom: 90,
|
queries: []*query{
|
||||||
|
{
|
||||||
|
sequenceFrom: 90,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set aggregateTypes",
|
||||||
|
args: args{
|
||||||
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testAddQuery(testSetAggregateTypes("user", "org"))},
|
||||||
|
},
|
||||||
|
res: &SearchQueryFactory{
|
||||||
|
queries: []*query{
|
||||||
|
{
|
||||||
|
aggregateTypes: []AggregateType{"user", "org"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "set aggregateIDs",
|
name: "set aggregateIDs",
|
||||||
args: args{
|
args: args{
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testSetAggregateIDs("1235", "09824")},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testAddQuery(testSetAggregateIDs("1235", "09824"))},
|
||||||
},
|
},
|
||||||
res: &SearchQueryFactory{
|
res: &SearchQueryFactory{
|
||||||
aggregateIDs: []string{"1235", "09824"},
|
queries: []*query{
|
||||||
|
{
|
||||||
|
aggregateIDs: []string{"1235", "09824"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "set eventTypes",
|
name: "set eventTypes",
|
||||||
args: args{
|
args: args{
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testSetEventTypes("user.created", "user.updated")},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testAddQuery(testSetEventTypes("user.created", "user.updated"))},
|
||||||
},
|
},
|
||||||
res: &SearchQueryFactory{
|
res: &SearchQueryFactory{
|
||||||
eventTypes: []EventType{"user.created", "user.updated"},
|
queries: []*query{
|
||||||
|
{
|
||||||
|
eventTypes: []EventType{"user.created", "user.updated"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "set resource owner",
|
name: "set resource owner",
|
||||||
args: args{
|
args: args{
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testSetResourceOwner("hodor")},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testAddQuery(testSetResourceOwner("hodor"))},
|
||||||
},
|
},
|
||||||
res: &SearchQueryFactory{
|
res: &SearchQueryFactory{
|
||||||
resourceOwner: "hodor",
|
queries: []*query{
|
||||||
|
{
|
||||||
|
resourceOwner: "hodor",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "default search query",
|
name: "default search query",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testAddQuery(testSetAggregateTypes("user"), testSetAggregateIDs("1235", "024")), testSetSortOrder(false)},
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{testSetAggregateIDs("1235", "024"), testSetSortOrder(false)},
|
|
||||||
},
|
},
|
||||||
res: &SearchQueryFactory{
|
res: &SearchQueryFactory{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
desc: true,
|
||||||
aggregateIDs: []string{"1235", "024"},
|
queries: []*query{
|
||||||
desc: true,
|
{
|
||||||
|
aggregateTypes: []AggregateType{"user"},
|
||||||
|
aggregateIDs: []string{"1235", "024"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
factory := NewSearchQueryFactory(tt.args.aggregateTypes...)
|
factory := NewSearchQueryFactory()
|
||||||
for _, setter := range tt.args.setters {
|
for _, setter := range tt.args.setters {
|
||||||
factory = setter(factory)
|
factory = setter(factory)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(factory, tt.res) {
|
assertFactory(t, tt.res, factory)
|
||||||
t.Errorf("NewSearchQueryFactory() = %v, want %v", factory, tt.res)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSearchQueryFactoryBuild(t *testing.T) {
|
func TestSearchQueryFactoryBuild(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
aggregateTypes []AggregateType
|
setters []func(*SearchQueryFactory) *SearchQueryFactory
|
||||||
setters []func(*SearchQueryFactory) *SearchQueryFactory
|
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
isErr func(err error) bool
|
isErr func(err error) bool
|
||||||
@@ -176,8 +260,7 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no aggregate types",
|
name: "no aggregate types",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{},
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{},
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
isErr: errors.IsPreconditionFailed,
|
isErr: errors.IsPreconditionFailed,
|
||||||
@@ -187,9 +270,9 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "invalid column (too low)",
|
name: "invalid column (too low)",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetColumns(Columns(-1)),
|
testSetColumns(Columns(-1)),
|
||||||
|
testAddQuery(testSetAggregateTypes("user")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -199,9 +282,9 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "invalid column (too high)",
|
name: "invalid column (too high)",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetColumns(columnsCount),
|
testSetColumns(columnsCount),
|
||||||
|
testAddQuery(testSetAggregateTypes("user")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -211,8 +294,9 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type",
|
name: "filter aggregate type",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{},
|
testAddQuery(testSetAggregateTypes("user")),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
isErr: nil,
|
isErr: nil,
|
||||||
@@ -220,8 +304,10 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -229,8 +315,9 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate types",
|
name: "filter aggregate types",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user", "org"},
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{},
|
testAddQuery(testSetAggregateTypes("user", "org")),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
isErr: nil,
|
isErr: nil,
|
||||||
@@ -238,8 +325,10 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, []AggregateType{"user", "org"}, Operation_In),
|
{
|
||||||
|
NewFilter(Field_AggregateType, []AggregateType{"user", "org"}, Operation_In),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -247,11 +336,13 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type, limit, desc",
|
name: "filter aggregate type, limit, desc",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetLimit(5),
|
testSetLimit(5),
|
||||||
testSetSortOrder(false),
|
testSetSortOrder(false),
|
||||||
testSetSequence(100),
|
testAddQuery(
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
testSetSequence(100),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -260,9 +351,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: true,
|
Desc: true,
|
||||||
Limit: 5,
|
Limit: 5,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_LatestSequence, uint64(100), Operation_Less),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_LatestSequence, uint64(100), Operation_Less),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -270,11 +363,13 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type, limit, asc",
|
name: "filter aggregate type, limit, asc",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetLimit(5),
|
testSetLimit(5),
|
||||||
testSetSortOrder(true),
|
testSetSortOrder(true),
|
||||||
testSetSequence(100),
|
testAddQuery(
|
||||||
|
testSetSequence(100),
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -283,9 +378,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 5,
|
Limit: 5,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_LatestSequence, uint64(100), Operation_Greater),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_LatestSequence, uint64(100), Operation_Greater),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -293,12 +390,14 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type, limit, desc, max event sequence cols",
|
name: "filter aggregate type, limit, desc, max event sequence cols",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetLimit(5),
|
testSetLimit(5),
|
||||||
testSetSortOrder(false),
|
testSetSortOrder(false),
|
||||||
testSetSequence(100),
|
|
||||||
testSetColumns(Columns_Max_Sequence),
|
testSetColumns(Columns_Max_Sequence),
|
||||||
|
testAddQuery(
|
||||||
|
testSetSequence(100),
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -307,9 +406,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: Columns_Max_Sequence,
|
Columns: Columns_Max_Sequence,
|
||||||
Desc: true,
|
Desc: true,
|
||||||
Limit: 5,
|
Limit: 5,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_LatestSequence, uint64(100), Operation_Less),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_LatestSequence, uint64(100), Operation_Less),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -317,9 +418,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type and aggregate id",
|
name: "filter aggregate type and aggregate id",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetAggregateIDs("1234"),
|
testAddQuery(
|
||||||
|
testSetAggregateIDs("1234"),
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -328,9 +431,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_AggregateID, "1234", Operation_Equals),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_AggregateID, "1234", Operation_Equals),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -338,9 +443,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type and aggregate ids",
|
name: "filter aggregate type and aggregate ids",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetAggregateIDs("1234", "0815"),
|
testAddQuery(
|
||||||
|
testSetAggregateIDs("1234", "0815"),
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -349,9 +456,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_AggregateID, []string{"1234", "0815"}, Operation_In),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_AggregateID, []string{"1234", "0815"}, Operation_In),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -359,9 +468,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type and sequence greater",
|
name: "filter aggregate type and sequence greater",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetSequence(8),
|
testAddQuery(
|
||||||
|
testSetSequence(8),
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -370,9 +481,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_LatestSequence, uint64(8), Operation_Greater),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_LatestSequence, uint64(8), Operation_Greater),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -380,9 +493,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type and event type",
|
name: "filter aggregate type and event type",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetEventTypes("user.created"),
|
testAddQuery(
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
testSetEventTypes("user.created"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -391,9 +506,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_EventType, EventType("user.created"), Operation_Equals),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_EventType, EventType("user.created"), Operation_Equals),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -401,9 +518,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type and event types",
|
name: "filter aggregate type and event types",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetEventTypes("user.created", "user.changed"),
|
testAddQuery(
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
testSetEventTypes("user.created", "user.changed"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -412,9 +531,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_EventType, []EventType{"user.created", "user.changed"}, Operation_In),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_EventType, []EventType{"user.created", "user.changed"}, Operation_In),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -422,9 +543,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter aggregate type resource owner",
|
name: "filter aggregate type resource owner",
|
||||||
args: args{
|
args: args{
|
||||||
aggregateTypes: []AggregateType{"user"},
|
|
||||||
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
setters: []func(*SearchQueryFactory) *SearchQueryFactory{
|
||||||
testSetResourceOwner("hodor"),
|
testAddQuery(
|
||||||
|
testSetAggregateTypes("user"),
|
||||||
|
testSetResourceOwner("hodor"),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@@ -433,9 +556,11 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
Columns: 0,
|
Columns: 0,
|
||||||
Desc: false,
|
Desc: false,
|
||||||
Limit: 0,
|
Limit: 0,
|
||||||
Filters: []*Filter{
|
Filters: [][]*Filter{
|
||||||
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
{
|
||||||
NewFilter(Field_ResourceOwner, "hodor", Operation_Equals),
|
NewFilter(Field_AggregateType, AggregateType("user"), Operation_Equals),
|
||||||
|
NewFilter(Field_ResourceOwner, "hodor", Operation_Equals),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -443,7 +568,7 @@ func TestSearchQueryFactoryBuild(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
factory := NewSearchQueryFactory(tt.args.aggregateTypes...)
|
factory := NewSearchQueryFactory()
|
||||||
for _, f := range tt.args.setters {
|
for _, f := range tt.args.setters {
|
||||||
factory = f(factory)
|
factory = f(factory)
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ type Handler interface {
|
|||||||
QueryLimit() uint64
|
QueryLimit() uint64
|
||||||
|
|
||||||
AggregateTypes() []models.AggregateType
|
AggregateTypes() []models.AggregateType
|
||||||
CurrentSequence() (uint64, error)
|
CurrentSequence(instanceID string) (uint64, error)
|
||||||
Eventstore() v1.Eventstore
|
Eventstore() v1.Eventstore
|
||||||
|
|
||||||
Subscription() *v1.Subscription
|
Subscription() *v1.Subscription
|
||||||
@@ -41,15 +41,18 @@ func ReduceEvent(handler Handler, event *models.Event) {
|
|||||||
handler.Subscription().Unsubscribe()
|
handler.Subscription().Unsubscribe()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
currentSequence, err := handler.CurrentSequence()
|
currentSequence, err := handler.CurrentSequence(event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.New().WithError(err).Warn("unable to get current sequence")
|
logging.New().WithError(err).Warn("unable to get current sequence")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
searchQuery := models.NewSearchQuery().
|
searchQuery := models.NewSearchQuery().
|
||||||
|
AddQuery().
|
||||||
AggregateTypeFilter(handler.AggregateTypes()...).
|
AggregateTypeFilter(handler.AggregateTypes()...).
|
||||||
SequenceBetween(currentSequence, event.Sequence).
|
SequenceBetween(currentSequence, event.Sequence).
|
||||||
|
InstanceIDFilter(event.InstanceID).
|
||||||
|
SearchQuery().
|
||||||
SetLimit(eventLimit)
|
SetLimit(eventLimit)
|
||||||
|
|
||||||
unprocessedEvents, err := handler.Eventstore().FilterEvents(context.Background(), searchQuery)
|
unprocessedEvents, err := handler.Eventstore().FilterEvents(context.Background(), searchQuery)
|
||||||
@@ -59,7 +62,7 @@ func ReduceEvent(handler Handler, event *models.Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, unprocessedEvent := range unprocessedEvents {
|
for _, unprocessedEvent := range unprocessedEvents {
|
||||||
currentSequence, err := handler.CurrentSequence()
|
currentSequence, err := handler.CurrentSequence(unprocessedEvent.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log("HANDL-BmpkC").WithError(err).Warn("unable to get current sequence")
|
logging.Log("HANDL-BmpkC").WithError(err).Warn("unable to get current sequence")
|
||||||
return
|
return
|
||||||
|
@@ -5,44 +5,45 @@
|
|||||||
package mock
|
package mock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gomock "github.com/golang/mock/gomock"
|
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
time "time"
|
time "time"
|
||||||
|
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockLocker is a mock of Locker interface
|
// MockLocker is a mock of Locker interface.
|
||||||
type MockLocker struct {
|
type MockLocker struct {
|
||||||
ctrl *gomock.Controller
|
ctrl *gomock.Controller
|
||||||
recorder *MockLockerMockRecorder
|
recorder *MockLockerMockRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// MockLockerMockRecorder is the mock recorder for MockLocker
|
// MockLockerMockRecorder is the mock recorder for MockLocker.
|
||||||
type MockLockerMockRecorder struct {
|
type MockLockerMockRecorder struct {
|
||||||
mock *MockLocker
|
mock *MockLocker
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMockLocker creates a new mock instance
|
// NewMockLocker creates a new mock instance.
|
||||||
func NewMockLocker(ctrl *gomock.Controller) *MockLocker {
|
func NewMockLocker(ctrl *gomock.Controller) *MockLocker {
|
||||||
mock := &MockLocker{ctrl: ctrl}
|
mock := &MockLocker{ctrl: ctrl}
|
||||||
mock.recorder = &MockLockerMockRecorder{mock}
|
mock.recorder = &MockLockerMockRecorder{mock}
|
||||||
return mock
|
return mock
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
func (m *MockLocker) EXPECT() *MockLockerMockRecorder {
|
func (m *MockLocker) EXPECT() *MockLockerMockRecorder {
|
||||||
return m.recorder
|
return m.recorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renew mocks base method
|
// Renew mocks base method.
|
||||||
func (m *MockLocker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
|
func (m *MockLocker) Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "Renew", lockerID, viewModel, waitTime)
|
ret := m.ctrl.Call(m, "Renew", lockerID, viewModel, instanceID, waitTime)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renew indicates an expected call of Renew
|
// Renew indicates an expected call of Renew.
|
||||||
func (mr *MockLockerMockRecorder) Renew(lockerID, viewModel, waitTime interface{}) *gomock.Call {
|
func (mr *MockLockerMockRecorder) Renew(lockerID, viewModel, instanceID, waitTime interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Renew", reflect.TypeOf((*MockLocker)(nil).Renew), lockerID, viewModel, waitTime)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Renew", reflect.TypeOf((*MockLocker)(nil).Renew), lockerID, viewModel, instanceID, waitTime)
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,8 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/view/repository"
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const systemID = "system"
|
||||||
|
|
||||||
type Spooler struct {
|
type Spooler struct {
|
||||||
handlers []query.Handler
|
handlers []query.Handler
|
||||||
locker Locker
|
locker Locker
|
||||||
@@ -26,7 +28,7 @@ type Spooler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Locker interface {
|
type Locker interface {
|
||||||
Renew(lockerID, viewModel string, waitTime time.Duration) error
|
Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type spooledHandler struct {
|
type spooledHandler struct {
|
||||||
@@ -138,19 +140,6 @@ func (s *spooledHandler) query(ctx context.Context) ([]*models.Event, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
factory := models.FactoryFromSearchQuery(query)
|
|
||||||
sequence, err := s.eventstore.LatestSequence(ctx, factory)
|
|
||||||
logging.OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("unable to query latest sequence")
|
|
||||||
var processedSequence uint64
|
|
||||||
for _, filter := range query.Filters {
|
|
||||||
if filter.GetField() == models.Field_LatestSequence {
|
|
||||||
processedSequence = filter.GetValue().(uint64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sequence != 0 && processedSequence == sequence {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
query.Limit = s.QueryLimit()
|
query.Limit = s.QueryLimit()
|
||||||
return s.eventstore.FilterEvents(ctx, query)
|
return s.eventstore.FilterEvents(ctx, query)
|
||||||
}
|
}
|
||||||
@@ -169,7 +158,7 @@ func (s *spooledHandler) lock(ctx context.Context, errs chan<- error, workerID s
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case <-renewTimer:
|
case <-renewTimer:
|
||||||
err := s.locker.Renew(workerID, s.ViewModel(), s.LockDuration())
|
err := s.locker.Renew(workerID, s.ViewModel(), systemID, s.LockDuration())
|
||||||
firstLock.Do(func() {
|
firstLock.Do(func() {
|
||||||
locked <- err == nil
|
locked <- err == nil
|
||||||
})
|
})
|
||||||
@@ -190,16 +179,17 @@ func (s *spooledHandler) lock(ctx context.Context, errs chan<- error, workerID s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HandleError(event *models.Event, failedErr error,
|
func HandleError(event *models.Event, failedErr error,
|
||||||
latestFailedEvent func(sequence uint64) (*repository.FailedEvent, error),
|
latestFailedEvent func(sequence uint64, instanceID string) (*repository.FailedEvent, error),
|
||||||
processFailedEvent func(*repository.FailedEvent) error,
|
processFailedEvent func(*repository.FailedEvent) error,
|
||||||
processSequence func(*models.Event) error,
|
processSequence func(*models.Event) error,
|
||||||
errorCountUntilSkip uint64) error {
|
errorCountUntilSkip uint64) error {
|
||||||
failedEvent, err := latestFailedEvent(event.Sequence)
|
failedEvent, err := latestFailedEvent(event.Sequence, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
failedEvent.FailureCount++
|
failedEvent.FailureCount++
|
||||||
failedEvent.ErrMsg = failedErr.Error()
|
failedEvent.ErrMsg = failedErr.Error()
|
||||||
|
failedEvent.InstanceID = event.InstanceID
|
||||||
err = processFailedEvent(failedEvent)
|
err = processFailedEvent(failedEvent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@@ -3,17 +3,18 @@ package spooler
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/caos/zitadel/internal/eventstore"
|
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore"
|
||||||
|
v1 "github.com/caos/zitadel/internal/eventstore/v1"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
"github.com/caos/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
"github.com/caos/zitadel/internal/eventstore/v1/query"
|
||||||
"github.com/caos/zitadel/internal/eventstore/v1/spooler/mock"
|
"github.com/caos/zitadel/internal/eventstore/v1/spooler/mock"
|
||||||
"github.com/caos/zitadel/internal/view/repository"
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
"github.com/golang/mock/gomock"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type testHandler struct {
|
type testHandler struct {
|
||||||
@@ -30,7 +31,7 @@ func (h *testHandler) AggregateTypes() []models.AggregateType {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *testHandler) CurrentSequence() (uint64, error) {
|
func (h *testHandler) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,8 +377,8 @@ func newTestLocker(t *testing.T, lockerID, viewName string) *testLocker {
|
|||||||
|
|
||||||
func (l *testLocker) expectRenew(t *testing.T, err error, waitTime time.Duration) *testLocker {
|
func (l *testLocker) expectRenew(t *testing.T, err error, waitTime time.Duration) *testLocker {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
l.mock.EXPECT().Renew(gomock.Any(), l.viewName, gomock.Any()).DoAndReturn(
|
l.mock.EXPECT().Renew(gomock.Any(), l.viewName, gomock.Any(), gomock.Any()).DoAndReturn(
|
||||||
func(_, _ string, gotten time.Duration) error {
|
func(_, _, _ string, gotten time.Duration) error {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if waitTime-gotten != 0 {
|
if waitTime-gotten != 0 {
|
||||||
t.Errorf("expected waittime %v got %v", waitTime, gotten)
|
t.Errorf("expected waittime %v got %v", waitTime, gotten)
|
||||||
@@ -396,7 +397,7 @@ func TestHandleError(t *testing.T) {
|
|||||||
type args struct {
|
type args struct {
|
||||||
event *models.Event
|
event *models.Event
|
||||||
failedErr error
|
failedErr error
|
||||||
latestFailedEvent func(sequence uint64) (*repository.FailedEvent, error)
|
latestFailedEvent func(sequence uint64, instanceID string) (*repository.FailedEvent, error)
|
||||||
errorCountUntilSkip uint64
|
errorCountUntilSkip uint64
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
@@ -413,12 +414,13 @@ func TestHandleError(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
event: &models.Event{Sequence: 30000000},
|
event: &models.Event{Sequence: 30000000},
|
||||||
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
||||||
latestFailedEvent: func(s uint64) (*repository.FailedEvent, error) {
|
latestFailedEvent: func(s uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return &repository.FailedEvent{
|
return &repository.FailedEvent{
|
||||||
ErrMsg: "blub",
|
ErrMsg: "blub",
|
||||||
FailedSequence: s - 1,
|
FailedSequence: s - 1,
|
||||||
FailureCount: 6,
|
FailureCount: 6,
|
||||||
ViewName: "super.table",
|
ViewName: "super.table",
|
||||||
|
InstanceID: instanceID,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
errorCountUntilSkip: 5,
|
errorCountUntilSkip: 5,
|
||||||
@@ -432,12 +434,13 @@ func TestHandleError(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
event: &models.Event{Sequence: 30000000},
|
event: &models.Event{Sequence: 30000000},
|
||||||
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
||||||
latestFailedEvent: func(s uint64) (*repository.FailedEvent, error) {
|
latestFailedEvent: func(s uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return &repository.FailedEvent{
|
return &repository.FailedEvent{
|
||||||
ErrMsg: "blub",
|
ErrMsg: "blub",
|
||||||
FailedSequence: s - 1,
|
FailedSequence: s - 1,
|
||||||
FailureCount: 5,
|
FailureCount: 5,
|
||||||
ViewName: "super.table",
|
ViewName: "super.table",
|
||||||
|
InstanceID: instanceID,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
errorCountUntilSkip: 6,
|
errorCountUntilSkip: 6,
|
||||||
@@ -451,12 +454,13 @@ func TestHandleError(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
event: &models.Event{Sequence: 30000000},
|
event: &models.Event{Sequence: 30000000},
|
||||||
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
failedErr: errors.ThrowInternal(nil, "SPOOL-Wk53B", "this was wrong"),
|
||||||
latestFailedEvent: func(s uint64) (*repository.FailedEvent, error) {
|
latestFailedEvent: func(s uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return &repository.FailedEvent{
|
return &repository.FailedEvent{
|
||||||
ErrMsg: "blub",
|
ErrMsg: "blub",
|
||||||
FailedSequence: s - 1,
|
FailedSequence: s - 1,
|
||||||
FailureCount: 3,
|
FailureCount: 3,
|
||||||
ViewName: "super.table",
|
ViewName: "super.table",
|
||||||
|
InstanceID: instanceID,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
errorCountUntilSkip: 5,
|
errorCountUntilSkip: 5,
|
||||||
|
@@ -36,6 +36,7 @@ const (
|
|||||||
IDPProviderSearchKeyAggregateID
|
IDPProviderSearchKeyAggregateID
|
||||||
IDPProviderSearchKeyIdpConfigID
|
IDPProviderSearchKeyIdpConfigID
|
||||||
IDPProviderSearchKeyState
|
IDPProviderSearchKeyState
|
||||||
|
IDPProviderSearchKeyInstanceID
|
||||||
)
|
)
|
||||||
|
|
||||||
type IDPProviderSearchQuery struct {
|
type IDPProviderSearchQuery struct {
|
||||||
|
@@ -1,19 +1,21 @@
|
|||||||
package view
|
package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
"github.com/caos/zitadel/internal/view/repository"
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
"github.com/jinzhu/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetIDPProviderByAggregateIDAndConfigID(db *gorm.DB, table, aggregateID, idpConfigID string) (*model.IDPProviderView, error) {
|
func GetIDPProviderByAggregateIDAndConfigID(db *gorm.DB, table, aggregateID, idpConfigID, instanceID string) (*model.IDPProviderView, error) {
|
||||||
policy := new(model.IDPProviderView)
|
policy := new(model.IDPProviderView)
|
||||||
aggIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
aggIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
||||||
idpConfigIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyIdpConfigID, Value: idpConfigID, Method: domain.SearchMethodEquals}
|
idpConfigIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyIdpConfigID, Value: idpConfigID, Method: domain.SearchMethodEquals}
|
||||||
query := repository.PrepareGetByQuery(table, aggIDQuery, idpConfigIDQuery)
|
instanceIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals}
|
||||||
|
query := repository.PrepareGetByQuery(table, aggIDQuery, idpConfigIDQuery, instanceIDQuery)
|
||||||
err := query(db, policy)
|
err := query(db, policy)
|
||||||
if caos_errs.IsNotFound(err) {
|
if caos_errs.IsNotFound(err) {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-Skvi8", "Errors.IAM.LoginPolicy.IDP.NotExisting")
|
return nil, caos_errs.ThrowNotFound(nil, "VIEW-Skvi8", "Errors.IAM.LoginPolicy.IDP.NotExisting")
|
||||||
@@ -21,7 +23,7 @@ func GetIDPProviderByAggregateIDAndConfigID(db *gorm.DB, table, aggregateID, idp
|
|||||||
return policy, err
|
return policy, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func IDPProvidersByIdpConfigID(db *gorm.DB, table string, idpConfigID string) ([]*model.IDPProviderView, error) {
|
func IDPProvidersByIdpConfigID(db *gorm.DB, table, idpConfigID, instanceID string) ([]*model.IDPProviderView, error) {
|
||||||
providers := make([]*model.IDPProviderView, 0)
|
providers := make([]*model.IDPProviderView, 0)
|
||||||
queries := []*iam_model.IDPProviderSearchQuery{
|
queries := []*iam_model.IDPProviderSearchQuery{
|
||||||
{
|
{
|
||||||
@@ -29,6 +31,11 @@ func IDPProvidersByIdpConfigID(db *gorm.DB, table string, idpConfigID string) ([
|
|||||||
Value: idpConfigID,
|
Value: idpConfigID,
|
||||||
Method: domain.SearchMethodEquals,
|
Method: domain.SearchMethodEquals,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Key: iam_model.IDPProviderSearchKeyInstanceID,
|
||||||
|
Value: instanceID,
|
||||||
|
Method: domain.SearchMethodEquals,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries})
|
query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries})
|
||||||
_, err := query(db, &providers)
|
_, err := query(db, &providers)
|
||||||
@@ -38,7 +45,7 @@ func IDPProvidersByIdpConfigID(db *gorm.DB, table string, idpConfigID string) ([
|
|||||||
return providers, nil
|
return providers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IDPProvidersByAggregateIDAndState(db *gorm.DB, table string, aggregateID string, idpConfigState iam_model.IDPConfigState) ([]*model.IDPProviderView, error) {
|
func IDPProvidersByAggregateIDAndState(db *gorm.DB, table string, aggregateID, instanceID string, idpConfigState iam_model.IDPConfigState) ([]*model.IDPProviderView, error) {
|
||||||
providers := make([]*model.IDPProviderView, 0)
|
providers := make([]*model.IDPProviderView, 0)
|
||||||
queries := []*iam_model.IDPProviderSearchQuery{
|
queries := []*iam_model.IDPProviderSearchQuery{
|
||||||
{
|
{
|
||||||
@@ -51,6 +58,11 @@ func IDPProvidersByAggregateIDAndState(db *gorm.DB, table string, aggregateID st
|
|||||||
Value: int(idpConfigState),
|
Value: int(idpConfigState),
|
||||||
Method: domain.SearchMethodEquals,
|
Method: domain.SearchMethodEquals,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Key: iam_model.IDPProviderSearchKeyInstanceID,
|
||||||
|
Value: instanceID,
|
||||||
|
Method: domain.SearchMethodEquals,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries})
|
query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries})
|
||||||
_, err := query(db, &providers)
|
_, err := query(db, &providers)
|
||||||
@@ -84,17 +96,19 @@ func PutIDPProviders(db *gorm.DB, table string, providers ...*model.IDPProviderV
|
|||||||
return save(db, p...)
|
return save(db, p...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteIDPProvider(db *gorm.DB, table, aggregateID, idpConfigID string) error {
|
func DeleteIDPProvider(db *gorm.DB, table, aggregateID, idpConfigID, instanceID string) error {
|
||||||
delete := repository.PrepareDeleteByKeys(table,
|
delete := repository.PrepareDeleteByKeys(table,
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID},
|
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID},
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyIdpConfigID), Value: idpConfigID},
|
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyIdpConfigID), Value: idpConfigID},
|
||||||
|
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID},
|
||||||
)
|
)
|
||||||
return delete(db)
|
return delete(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteIDPProvidersByAggregateID(db *gorm.DB, table, aggregateID string) error {
|
func DeleteIDPProvidersByAggregateID(db *gorm.DB, table, aggregateID, instanceID string) error {
|
||||||
delete := repository.PrepareDeleteByKeys(table,
|
delete := repository.PrepareDeleteByKeys(table,
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID},
|
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID},
|
||||||
|
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID},
|
||||||
)
|
)
|
||||||
return delete(db)
|
return delete(db)
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,20 @@
|
|||||||
package view
|
package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/domain"
|
"github.com/caos/zitadel/internal/domain"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||||
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
"github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||||
"github.com/caos/zitadel/internal/view/repository"
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
"github.com/jinzhu/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func IDPByID(db *gorm.DB, table, idpID string) (*model.IDPConfigView, error) {
|
func IDPByID(db *gorm.DB, table, idpID, instanceID string) (*model.IDPConfigView, error) {
|
||||||
idp := new(model.IDPConfigView)
|
idp := new(model.IDPConfigView)
|
||||||
idpIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyIdpConfigID, Value: idpID, Method: domain.SearchMethodEquals}
|
idpIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyIdpConfigID, Value: idpID, Method: domain.SearchMethodEquals}
|
||||||
query := repository.PrepareGetByQuery(table, idpIDQuery)
|
instanceIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals}
|
||||||
|
query := repository.PrepareGetByQuery(table, idpIDQuery, instanceIDQuery)
|
||||||
err := query(db, idp)
|
err := query(db, idp)
|
||||||
if caos_errs.IsNotFound(err) {
|
if caos_errs.IsNotFound(err) {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-Ahq2s", "Errors.IDP.NotExisting")
|
return nil, caos_errs.ThrowNotFound(nil, "VIEW-Ahq2s", "Errors.IDP.NotExisting")
|
||||||
@@ -20,13 +22,17 @@ func IDPByID(db *gorm.DB, table, idpID string) (*model.IDPConfigView, error) {
|
|||||||
return idp, err
|
return idp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetIDPConfigsByAggregateID(db *gorm.DB, table string, aggregateID string) ([]*model.IDPConfigView, error) {
|
func GetIDPConfigsByAggregateID(db *gorm.DB, table string, aggregateID, instanceID string) ([]*model.IDPConfigView, error) {
|
||||||
idps := make([]*model.IDPConfigView, 0)
|
idps := make([]*model.IDPConfigView, 0)
|
||||||
queries := []*iam_model.IDPConfigSearchQuery{
|
queries := []*iam_model.IDPConfigSearchQuery{
|
||||||
{
|
{
|
||||||
Key: iam_model.IDPConfigSearchKeyAggregateID,
|
Key: iam_model.IDPConfigSearchKeyAggregateID,
|
||||||
Value: aggregateID,
|
Value: aggregateID,
|
||||||
Method: domain.SearchMethodEquals,
|
Method: domain.SearchMethodEquals,
|
||||||
|
}, {
|
||||||
|
Key: iam_model.IDPConfigSearchKeyInstanceID,
|
||||||
|
Value: instanceID,
|
||||||
|
Method: domain.SearchMethodEquals,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPConfigSearchRequest{Queries: queries})
|
query := repository.PrepareSearchQuery(table, model.IDPConfigSearchRequest{Queries: queries})
|
||||||
@@ -52,8 +58,11 @@ func PutIDP(db *gorm.DB, table string, idp *model.IDPConfigView) error {
|
|||||||
return save(db, idp)
|
return save(db, idp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteIDP(db *gorm.DB, table, idpID string) error {
|
func DeleteIDP(db *gorm.DB, table, idpID, instanceID string) error {
|
||||||
delete := repository.PrepareDeleteByKey(table, model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyIdpConfigID), idpID)
|
delete := repository.PrepareDeleteByKeys(table,
|
||||||
|
repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyIdpConfigID), idpID},
|
||||||
|
repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID},
|
||||||
|
)
|
||||||
|
|
||||||
return delete(db)
|
return delete(db)
|
||||||
}
|
}
|
||||||
|
@@ -50,7 +50,7 @@ type IDPConfigView struct {
|
|||||||
JWTHeaderName string `json:"headerName" gorm:"jwt_header_name"`
|
JWTHeaderName string `json:"headerName" gorm:"jwt_header_name"`
|
||||||
|
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||||
InstanceID string `json:"instanceID" gorm:"column:instance_id"`
|
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func IDPConfigViewToModel(idp *IDPConfigView) *model.IDPConfigView {
|
func IDPConfigViewToModel(idp *IDPConfigView) *model.IDPConfigView {
|
||||||
|
@@ -18,6 +18,7 @@ const (
|
|||||||
IDPProviderKeyAggregateID = "aggregate_id"
|
IDPProviderKeyAggregateID = "aggregate_id"
|
||||||
IDPProviderKeyIdpConfigID = "idp_config_id"
|
IDPProviderKeyIdpConfigID = "idp_config_id"
|
||||||
IDPProviderKeyState = "idp_state"
|
IDPProviderKeyState = "idp_state"
|
||||||
|
IDPProviderKeyInstanceID = "instance_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IDPProviderView struct {
|
type IDPProviderView struct {
|
||||||
@@ -34,7 +35,7 @@ type IDPProviderView struct {
|
|||||||
IDPState int32 `json:"-" gorm:"column:idp_state"`
|
IDPState int32 `json:"-" gorm:"column:idp_state"`
|
||||||
|
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||||
InstanceID string `json:"instanceID" gorm:"column:instance_id"`
|
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func IDPProviderViewToModel(provider *IDPProviderView) *model.IDPProviderView {
|
func IDPProviderViewToModel(provider *IDPProviderView) *model.IDPProviderView {
|
||||||
|
@@ -57,6 +57,8 @@ func (key IDPProviderSearchKey) ToColumnName() string {
|
|||||||
return IDPProviderKeyIdpConfigID
|
return IDPProviderKeyIdpConfigID
|
||||||
case iam_model.IDPProviderSearchKeyState:
|
case iam_model.IDPProviderSearchKeyState:
|
||||||
return IDPProviderKeyState
|
return IDPProviderKeyState
|
||||||
|
case iam_model.IDPProviderSearchKeyInstanceID:
|
||||||
|
return IDPProviderKeyInstanceID
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,7 @@ type LabelPolicyView struct {
|
|||||||
Default bool `json:"-" gorm:"-"`
|
Default bool `json:"-" gorm:"-"`
|
||||||
|
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||||
InstanceID string `json:"instanceID" gorm:"column:instance_id"`
|
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AssetView struct {
|
type AssetView struct {
|
||||||
|
@@ -10,11 +10,12 @@ import (
|
|||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetStylingByAggregateIDAndState(db *gorm.DB, table, aggregateID string, state int32) (*model.LabelPolicyView, error) {
|
func GetStylingByAggregateIDAndState(db *gorm.DB, table, aggregateID, instanceID string, state int32) (*model.LabelPolicyView, error) {
|
||||||
policy := new(model.LabelPolicyView)
|
policy := new(model.LabelPolicyView)
|
||||||
aggregateIDQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
aggregateIDQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
||||||
stateQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyState, Value: state, Method: domain.SearchMethodEquals}
|
stateQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyState, Value: state, Method: domain.SearchMethodEquals}
|
||||||
query := repository.PrepareGetByQuery(table, aggregateIDQuery, stateQuery)
|
instanceIDQuery := &model.LabelPolicySearchQuery{Key: iam_model.LabelPolicySearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals}
|
||||||
|
query := repository.PrepareGetByQuery(table, aggregateIDQuery, stateQuery, instanceIDQuery)
|
||||||
err := query(db, policy)
|
err := query(db, policy)
|
||||||
if caos_errs.IsNotFound(err) {
|
if caos_errs.IsNotFound(err) {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-68G11", "Errors.IAM.LabelPolicy.NotExisting")
|
return nil, caos_errs.ThrowNotFound(nil, "VIEW-68G11", "Errors.IAM.LabelPolicy.NotExisting")
|
||||||
|
@@ -99,8 +99,8 @@ func (_ *Notification) AggregateTypes() []models.AggregateType {
|
|||||||
return []models.AggregateType{user_repo.AggregateType}
|
return []models.AggregateType{user_repo.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) CurrentSequence() (uint64, error) {
|
func (n *Notification) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := n.view.GetLatestNotificationSequence()
|
sequence, err := n.view.GetLatestNotificationSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -108,11 +108,29 @@ func (n *Notification) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) EventQuery() (*models.SearchQuery, error) {
|
func (n *Notification) EventQuery() (*models.SearchQuery, error) {
|
||||||
sequence, err := n.view.GetLatestNotificationSequence()
|
sequences, err := n.view.GetLatestNotificationSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return view.UserQuery(sequence.CurrentSequence), nil
|
query := models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(n.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
|
AggregateTypeFilter(n.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) Reduce(event *models.Event) (err error) {
|
func (n *Notification) Reduce(event *models.Event) (err error) {
|
||||||
@@ -162,7 +180,7 @@ func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := n.getUserByID(event.AggregateID)
|
user, err := n.getUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -201,7 +219,7 @@ func (n *Notification) handlePasswordCode(event *models.Event) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := n.getUserByID(event.AggregateID)
|
user, err := n.getUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -239,7 +257,7 @@ func (n *Notification) handleEmailVerificationCode(event *models.Event) (err err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := n.getUserByID(event.AggregateID)
|
user, err := n.getUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -268,7 +286,7 @@ func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err err
|
|||||||
if err != nil || alreadyHandled {
|
if err != nil || alreadyHandled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
user, err := n.getUserByID(event.AggregateID)
|
user, err := n.getUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -285,7 +303,7 @@ func (n *Notification) handlePhoneVerificationCode(event *models.Event) (err err
|
|||||||
|
|
||||||
func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
|
func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
|
||||||
ctx := getSetNotifyContextData(event.InstanceID, event.ResourceOwner)
|
ctx := getSetNotifyContextData(event.InstanceID, event.ResourceOwner)
|
||||||
alreadyHandled, err := n.checkIfAlreadyHandled(ctx, event.AggregateID, event.Sequence, user_repo.UserDomainClaimedType, user_repo.UserDomainClaimedSentType)
|
alreadyHandled, err := n.checkIfAlreadyHandled(ctx, event.AggregateID, event.InstanceID, event.Sequence, user_repo.UserDomainClaimedType, user_repo.UserDomainClaimedSentType)
|
||||||
if err != nil || alreadyHandled {
|
if err != nil || alreadyHandled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -294,7 +312,7 @@ func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
|
|||||||
logging.Log("HANDLE-Gghq2").WithError(err).Error("could not unmarshal event data")
|
logging.Log("HANDLE-Gghq2").WithError(err).Error("could not unmarshal event data")
|
||||||
return errors.ThrowInternal(err, "HANDLE-7hgj3", "could not unmarshal event")
|
return errors.ThrowInternal(err, "HANDLE-7hgj3", "could not unmarshal event")
|
||||||
}
|
}
|
||||||
user, err := n.getUserByID(event.AggregateID)
|
user, err := n.getUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -329,7 +347,7 @@ func (n *Notification) handlePasswordlessRegistrationLink(event *models.Event) (
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ctx := getSetNotifyContextData(event.InstanceID, event.ResourceOwner)
|
ctx := getSetNotifyContextData(event.InstanceID, event.ResourceOwner)
|
||||||
events, err := n.getUserEvents(ctx, event.AggregateID, event.Sequence)
|
events, err := n.getUserEvents(ctx, event.AggregateID, event.InstanceID, event.Sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -344,7 +362,7 @@ func (n *Notification) handlePasswordlessRegistrationLink(event *models.Event) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user, err := n.getUserByID(event.AggregateID)
|
user, err := n.getUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -374,11 +392,11 @@ func (n *Notification) checkIfCodeAlreadyHandledOrExpired(ctx context.Context, e
|
|||||||
if event.CreationDate.Add(expiry).Before(time.Now().UTC()) {
|
if event.CreationDate.Add(expiry).Before(time.Now().UTC()) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
return n.checkIfAlreadyHandled(ctx, event.AggregateID, event.Sequence, eventTypes...)
|
return n.checkIfAlreadyHandled(ctx, event.AggregateID, event.InstanceID, event.Sequence, eventTypes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) checkIfAlreadyHandled(ctx context.Context, userID string, sequence uint64, eventTypes ...eventstore.EventType) (bool, error) {
|
func (n *Notification) checkIfAlreadyHandled(ctx context.Context, userID, instanceID string, sequence uint64, eventTypes ...eventstore.EventType) (bool, error) {
|
||||||
events, err := n.getUserEvents(ctx, userID, sequence)
|
events, err := n.getUserEvents(ctx, userID, instanceID, sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@@ -392,8 +410,8 @@ func (n *Notification) checkIfAlreadyHandled(ctx context.Context, userID string,
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) getUserEvents(ctx context.Context, userID string, sequence uint64) ([]*models.Event, error) {
|
func (n *Notification) getUserEvents(ctx context.Context, userID, instanceID string, sequence uint64) ([]*models.Event, error) {
|
||||||
query, err := view.UserByIDQuery(userID, sequence)
|
query, err := view.UserByIDQuery(userID, instanceID, sequence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -514,6 +532,6 @@ func (n *Notification) getTranslatorWithOrgTexts(ctx context.Context, orgID, tex
|
|||||||
return translator, nil
|
return translator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) getUserByID(userID string) (*model.NotifyUser, error) {
|
func (n *Notification) getUserByID(userID, instanceID string) (*model.NotifyUser, error) {
|
||||||
return n.view.NotifyUserByID(userID)
|
return n.view.NotifyUserByID(userID, instanceID)
|
||||||
}
|
}
|
||||||
|
@@ -67,8 +67,8 @@ func (_ *NotifyUser) AggregateTypes() []es_models.AggregateType {
|
|||||||
return []es_models.AggregateType{user.AggregateType, org.AggregateType}
|
return []es_models.AggregateType{user.AggregateType, org.AggregateType}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *NotifyUser) CurrentSequence() (uint64, error) {
|
func (p *NotifyUser) CurrentSequence(instanceID string) (uint64, error) {
|
||||||
sequence, err := p.view.GetLatestNotifyUserSequence()
|
sequence, err := p.view.GetLatestNotifyUserSequence(instanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -76,13 +76,29 @@ func (p *NotifyUser) CurrentSequence() (uint64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *NotifyUser) EventQuery() (*es_models.SearchQuery, error) {
|
func (p *NotifyUser) EventQuery() (*es_models.SearchQuery, error) {
|
||||||
sequence, err := p.view.GetLatestNotifyUserSequence()
|
sequences, err := p.view.GetLatestNotifyUserSequences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return es_models.NewSearchQuery().
|
query := es_models.NewSearchQuery()
|
||||||
|
instances := make([]string, 0)
|
||||||
|
for _, sequence := range sequences {
|
||||||
|
for _, instance := range instances {
|
||||||
|
if sequence.InstanceID == instance {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instances = append(instances, sequence.InstanceID)
|
||||||
|
query.AddQuery().
|
||||||
|
AggregateTypeFilter(p.AggregateTypes()...).
|
||||||
|
LatestSequenceFilter(sequence.CurrentSequence).
|
||||||
|
InstanceIDFilter(sequence.InstanceID)
|
||||||
|
}
|
||||||
|
return query.AddQuery().
|
||||||
AggregateTypeFilter(p.AggregateTypes()...).
|
AggregateTypeFilter(p.AggregateTypes()...).
|
||||||
LatestSequenceFilter(sequence.CurrentSequence), nil
|
LatestSequenceFilter(0).
|
||||||
|
ExcludedInstanceIDsFilter(instances...).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *NotifyUser) Reduce(event *es_models.Event) (err error) {
|
func (u *NotifyUser) Reduce(event *es_models.Event) (err error) {
|
||||||
@@ -122,14 +138,14 @@ func (u *NotifyUser) ProcessUser(event *es_models.Event) (err error) {
|
|||||||
user.HumanPhoneVerifiedType,
|
user.HumanPhoneVerifiedType,
|
||||||
user.HumanPhoneRemovedType,
|
user.HumanPhoneRemovedType,
|
||||||
user.MachineChangedEventType:
|
user.MachineChangedEventType:
|
||||||
notifyUser, err = u.view.NotifyUserByID(event.AggregateID)
|
notifyUser, err = u.view.NotifyUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = notifyUser.AppendEvent(event)
|
err = notifyUser.AppendEvent(event)
|
||||||
case user.UserDomainClaimedType,
|
case user.UserDomainClaimedType,
|
||||||
user.UserUserNameChangedType:
|
user.UserUserNameChangedType:
|
||||||
notifyUser, err = u.view.NotifyUserByID(event.AggregateID)
|
notifyUser, err = u.view.NotifyUserByID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -139,7 +155,7 @@ func (u *NotifyUser) ProcessUser(event *es_models.Event) (err error) {
|
|||||||
}
|
}
|
||||||
err = u.fillLoginNames(notifyUser)
|
err = u.fillLoginNames(notifyUser)
|
||||||
case user.UserRemovedType:
|
case user.UserRemovedType:
|
||||||
return u.view.DeleteNotifyUser(event.AggregateID, event)
|
return u.view.DeleteNotifyUser(event.AggregateID, event.InstanceID, event)
|
||||||
default:
|
default:
|
||||||
return u.view.ProcessedNotifyUserSequence(event)
|
return u.view.ProcessedNotifyUserSequence(event)
|
||||||
}
|
}
|
||||||
@@ -169,7 +185,7 @@ func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *es_models.Event) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
users, err := u.view.NotifyUsersByOrgID(event.AggregateID)
|
users, err := u.view.NotifyUsersByOrgID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -191,7 +207,7 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *es_models.Event) e
|
|||||||
if !userLoginMustBeDomain {
|
if !userLoginMustBeDomain {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
users, err := u.view.NotifyUsersByOrgID(event.AggregateID)
|
users, err := u.view.NotifyUsersByOrgID(event.AggregateID, event.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -2,8 +2,9 @@ package spooler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
es_locker "github.com/caos/zitadel/internal/eventstore/v1/locker"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
es_locker "github.com/caos/zitadel/internal/eventstore/v1/locker"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -14,6 +15,6 @@ type locker struct {
|
|||||||
dbClient *sql.DB
|
dbClient *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error {
|
func (l *locker) Renew(lockerID, viewModel, instanceID string, waitTime time.Duration) error {
|
||||||
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime)
|
return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, instanceID, waitTime)
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,6 @@ func (v *View) saveFailedEvent(failedEvent *repository.FailedEvent) error {
|
|||||||
return repository.SaveFailedEvent(v.Db, errTable, failedEvent)
|
return repository.SaveFailedEvent(v.Db, errTable, failedEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestFailedEvent(viewName string, sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) latestFailedEvent(viewName, instanceID string, sequence uint64) (*repository.FailedEvent, error) {
|
||||||
return repository.LatestFailedEvent(v.Db, errTable, viewName, sequence)
|
return repository.LatestFailedEvent(v.Db, errTable, viewName, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
@@ -9,8 +9,12 @@ const (
|
|||||||
notificationTable = "notification.notifications"
|
notificationTable = "notification.notifications"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) GetLatestNotificationSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestNotificationSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(notificationTable)
|
return v.latestSequence(notificationTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestNotificationSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(notificationTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedNotificationSequence(event *models.Event) error {
|
func (v *View) ProcessedNotificationSequence(event *models.Event) error {
|
||||||
@@ -21,8 +25,8 @@ func (v *View) UpdateNotificationSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(notificationTable)
|
return v.updateSpoolerRunSequence(notificationTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestNotificationFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestNotificationFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(notificationTable, sequence)
|
return v.latestFailedEvent(notificationTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedNotificationFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedNotificationFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -12,8 +12,8 @@ const (
|
|||||||
notifyUserTable = "notification.notify_users"
|
notifyUserTable = "notification.notify_users"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) NotifyUserByID(userID string) (*model.NotifyUser, error) {
|
func (v *View) NotifyUserByID(userID, instanceID string) (*model.NotifyUser, error) {
|
||||||
return view.NotifyUserByID(v.Db, notifyUserTable, userID)
|
return view.NotifyUserByID(v.Db, notifyUserTable, userID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) PutNotifyUser(user *model.NotifyUser, event *models.Event) error {
|
func (v *View) PutNotifyUser(user *model.NotifyUser, event *models.Event) error {
|
||||||
@@ -24,20 +24,24 @@ func (v *View) PutNotifyUser(user *model.NotifyUser, event *models.Event) error
|
|||||||
return v.ProcessedNotifyUserSequence(event)
|
return v.ProcessedNotifyUserSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) NotifyUsersByOrgID(orgID string) ([]*model.NotifyUser, error) {
|
func (v *View) NotifyUsersByOrgID(orgID, instanceID string) ([]*model.NotifyUser, error) {
|
||||||
return view.NotifyUsersByOrgID(v.Db, notifyUserTable, orgID)
|
return view.NotifyUsersByOrgID(v.Db, notifyUserTable, orgID, instanceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) DeleteNotifyUser(userID string, event *models.Event) error {
|
func (v *View) DeleteNotifyUser(userID, instanceID string, event *models.Event) error {
|
||||||
err := view.DeleteNotifyUser(v.Db, notifyUserTable, userID)
|
err := view.DeleteNotifyUser(v.Db, notifyUserTable, userID, instanceID)
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return v.ProcessedNotifyUserSequence(event)
|
return v.ProcessedNotifyUserSequence(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestNotifyUserSequence() (*repository.CurrentSequence, error) {
|
func (v *View) GetLatestNotifyUserSequence(instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return v.latestSequence(notifyUserTable)
|
return v.latestSequence(notifyUserTable, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) GetLatestNotifyUserSequences() ([]*repository.CurrentSequence, error) {
|
||||||
|
return v.latestSequences(notifyUserTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedNotifyUserSequence(event *models.Event) error {
|
func (v *View) ProcessedNotifyUserSequence(event *models.Event) error {
|
||||||
@@ -48,8 +52,8 @@ func (v *View) UpdateNotifyUserSpoolerRunTimestamp() error {
|
|||||||
return v.updateSpoolerRunSequence(notifyUserTable)
|
return v.updateSpoolerRunSequence(notifyUserTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) GetLatestNotifyUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
|
func (v *View) GetLatestNotifyUserFailedEvent(sequence uint64, instanceID string) (*repository.FailedEvent, error) {
|
||||||
return v.latestFailedEvent(notifyUserTable, sequence)
|
return v.latestFailedEvent(notifyUserTable, instanceID, sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) ProcessedNotifyUserFailedEvent(failedEvent *repository.FailedEvent) error {
|
func (v *View) ProcessedNotifyUserFailedEvent(failedEvent *repository.FailedEvent) error {
|
||||||
|
@@ -12,21 +12,27 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
func (v *View) saveCurrentSequence(viewName string, event *models.Event) error {
|
||||||
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.Sequence, event.CreationDate)
|
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, event.InstanceID, event.Sequence, event.CreationDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
|
func (v *View) latestSequence(viewName, instanceID string) (*repository.CurrentSequence, error) {
|
||||||
return repository.LatestSequence(v.Db, sequencesTable, viewName)
|
return repository.LatestSequence(v.Db, sequencesTable, viewName, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *View) latestSequences(viewName string) ([]*repository.CurrentSequence, error) {
|
||||||
|
return repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
func (v *View) updateSpoolerRunSequence(viewName string) error {
|
||||||
currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
|
currentSequences, err := repository.LatestSequences(v.Db, sequencesTable, viewName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if currentSequence.ViewName == "" {
|
for _, currentSequence := range currentSequences {
|
||||||
currentSequence.ViewName = viewName
|
if currentSequence.ViewName == "" {
|
||||||
|
currentSequence.ViewName = viewName
|
||||||
|
}
|
||||||
|
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
||||||
}
|
}
|
||||||
currentSequence.LastSuccessfulSpoolerRun = time.Now()
|
return repository.UpdateCurrentSequences(v.Db, sequencesTable, currentSequences)
|
||||||
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
|
|
||||||
}
|
}
|
||||||
|
@@ -11,11 +11,15 @@ func OrgByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, err
|
|||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "id should be filled")
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "id should be filled")
|
||||||
}
|
}
|
||||||
return OrgQuery(latestSequence).
|
return OrgQuery(latestSequence).
|
||||||
AggregateIDFilter(id), nil
|
AddQuery().
|
||||||
|
AggregateIDFilter(id).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func OrgQuery(latestSequence uint64) *es_models.SearchQuery {
|
func OrgQuery(latestSequence uint64) *es_models.SearchQuery {
|
||||||
return es_models.NewSearchQuery().
|
return es_models.NewSearchQuery().
|
||||||
|
AddQuery().
|
||||||
AggregateTypeFilter(org.AggregateType).
|
AggregateTypeFilter(org.AggregateType).
|
||||||
LatestSequenceFilter(latestSequence)
|
LatestSequenceFilter(latestSequence).
|
||||||
|
SearchQuery()
|
||||||
}
|
}
|
||||||
|
@@ -10,12 +10,13 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/view/repository"
|
"github.com/caos/zitadel/internal/view/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
func OrgProjectMappingByIDs(db *gorm.DB, table, orgID, projectID string) (*model.OrgProjectMapping, error) {
|
func OrgProjectMappingByIDs(db *gorm.DB, table, orgID, projectID, instanceID string) (*model.OrgProjectMapping, error) {
|
||||||
orgProjectMapping := new(model.OrgProjectMapping)
|
orgProjectMapping := new(model.OrgProjectMapping)
|
||||||
|
|
||||||
projectIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyProjectID, Value: projectID, Method: domain.SearchMethodEquals}
|
projectIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyProjectID, Value: projectID, Method: domain.SearchMethodEquals}
|
||||||
orgIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyOrgID, Value: orgID, Method: domain.SearchMethodEquals}
|
orgIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyOrgID, Value: orgID, Method: domain.SearchMethodEquals}
|
||||||
query := repository.PrepareGetByQuery(table, projectIDQuery, orgIDQuery)
|
instanceIDQuery := model.OrgProjectMappingSearchQuery{Key: proj_model.OrgProjectMappingSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals}
|
||||||
|
query := repository.PrepareGetByQuery(table, projectIDQuery, orgIDQuery, instanceIDQuery)
|
||||||
err := query(db, orgProjectMapping)
|
err := query(db, orgProjectMapping)
|
||||||
if caos_errs.IsNotFound(err) {
|
if caos_errs.IsNotFound(err) {
|
||||||
return nil, caos_errs.ThrowNotFound(nil, "VIEW-fn9fs", "Errors.OrgProjectMapping.NotExisting")
|
return nil, caos_errs.ThrowNotFound(nil, "VIEW-fn9fs", "Errors.OrgProjectMapping.NotExisting")
|
||||||
@@ -28,19 +29,26 @@ func PutOrgProjectMapping(db *gorm.DB, table string, grant *model.OrgProjectMapp
|
|||||||
return save(db, grant)
|
return save(db, grant)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteOrgProjectMapping(db *gorm.DB, table, orgID, projectID string) error {
|
func DeleteOrgProjectMapping(db *gorm.DB, table, orgID, projectID, instanceID string) error {
|
||||||
projectIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), Value: projectID}
|
projectIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), Value: projectID}
|
||||||
orgIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyOrgID), Value: orgID}
|
orgIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyOrgID), Value: orgID}
|
||||||
delete := repository.PrepareDeleteByKeys(table, projectIDSearch, orgIDSearch)
|
instanceIDSearch := repository.Key{Key: model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), Value: instanceID}
|
||||||
|
delete := repository.PrepareDeleteByKeys(table, projectIDSearch, orgIDSearch, instanceIDSearch)
|
||||||
return delete(db)
|
return delete(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteOrgProjectMappingsByProjectID(db *gorm.DB, table, projectID string) error {
|
func DeleteOrgProjectMappingsByProjectID(db *gorm.DB, table, projectID, instanceID string) error {
|
||||||
delete := repository.PrepareDeleteByKey(table, model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), projectID)
|
delete := repository.PrepareDeleteByKeys(table,
|
||||||
|
repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectID), projectID},
|
||||||
|
repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), instanceID},
|
||||||
|
)
|
||||||
return delete(db)
|
return delete(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteOrgProjectMappingsByProjectGrantID(db *gorm.DB, table, projectGrantID string) error {
|
func DeleteOrgProjectMappingsByProjectGrantID(db *gorm.DB, table, projectGrantID, instanceID string) error {
|
||||||
delete := repository.PrepareDeleteByKey(table, model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectGrantID), projectGrantID)
|
delete := repository.PrepareDeleteByKeys(table,
|
||||||
|
repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyProjectGrantID), projectGrantID},
|
||||||
|
repository.Key{model.OrgProjectMappingSearchKey(proj_model.OrgProjectMappingSearchKeyInstanceID), instanceID},
|
||||||
|
)
|
||||||
return delete(db)
|
return delete(db)
|
||||||
}
|
}
|
||||||
|
@@ -6,16 +6,21 @@ import (
|
|||||||
"github.com/caos/zitadel/internal/repository/project"
|
"github.com/caos/zitadel/internal/repository/project"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
|
func ProjectByIDQuery(id, instanceID string, latestSequence uint64) (*es_models.SearchQuery, error) {
|
||||||
if id == "" {
|
if id == "" {
|
||||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "Errors.Project.ProjectIDMissing")
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "Errors.Project.ProjectIDMissing")
|
||||||
}
|
}
|
||||||
return ProjectQuery(latestSequence).
|
return ProjectQuery(latestSequence).
|
||||||
AggregateIDFilter(id), nil
|
AddQuery().
|
||||||
|
AggregateIDFilter(id).
|
||||||
|
InstanceIDFilter(instanceID).
|
||||||
|
SearchQuery(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectQuery(latestSequence uint64) *es_models.SearchQuery {
|
func ProjectQuery(latestSequence uint64) *es_models.SearchQuery {
|
||||||
return es_models.NewSearchQuery().
|
return es_models.NewSearchQuery().
|
||||||
|
AddQuery().
|
||||||
AggregateTypeFilter(project.AggregateType).
|
AggregateTypeFilter(project.AggregateType).
|
||||||
LatestSequenceFilter(latestSequence)
|
LatestSequenceFilter(latestSequence).
|
||||||
|
SearchQuery()
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/query/projection"
|
"github.com/caos/zitadel/internal/query/projection"
|
||||||
)
|
)
|
||||||
@@ -72,6 +73,7 @@ func (q *Queries) latestSequence(ctx context.Context, projections ...table) (*La
|
|||||||
}
|
}
|
||||||
stmt, args, err := query.
|
stmt, args, err := query.
|
||||||
Where(or).
|
Where(or).
|
||||||
|
Where(sq.Eq{CurrentSequenceColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}).
|
||||||
OrderBy(CurrentSequenceColCurrentSequence.identifier()).
|
OrderBy(CurrentSequenceColCurrentSequence.identifier()).
|
||||||
ToSql()
|
ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -269,6 +271,10 @@ var (
|
|||||||
name: "projection_name",
|
name: "projection_name",
|
||||||
table: currentSequencesTable,
|
table: currentSequencesTable,
|
||||||
}
|
}
|
||||||
|
CurrentSequenceColInstanceID = Column{
|
||||||
|
name: "instance_id",
|
||||||
|
table: currentSequencesTable,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@@ -65,7 +65,7 @@ var (
|
|||||||
" , IFNULL(policy_custom.%[1]s, policy_default.%[1]s) AS %[1]s"+
|
" , IFNULL(policy_custom.%[1]s, policy_default.%[1]s) AS %[1]s"+
|
||||||
" FROM %[7]s users"+
|
" FROM %[7]s users"+
|
||||||
" LEFT JOIN %[8]s policy_custom on policy_custom.%[9]s = users.%[5]s AND policy_custom.%[10]s = users.%[4]s"+
|
" LEFT JOIN %[8]s policy_custom on policy_custom.%[9]s = users.%[5]s AND policy_custom.%[10]s = users.%[4]s"+
|
||||||
" LEFT JOIN %[8]s policy_default on policy_default.%[11]s = true) policy_users"+
|
" LEFT JOIN %[8]s policy_default on policy_default.%[11]s = true AND policy_default.%[10]s = users.%[4]s) policy_users"+
|
||||||
" LEFT JOIN %[12]s domains ON policy_users.%[1]s AND policy_users.%[5]s = domains.%[13]s AND policy_users.%[10]s = domains.%[14]s"+
|
" LEFT JOIN %[12]s domains ON policy_users.%[1]s AND policy_users.%[5]s = domains.%[13]s AND policy_users.%[10]s = domains.%[14]s"+
|
||||||
");",
|
");",
|
||||||
LoginNamePoliciesMustBeDomainCol,
|
LoginNamePoliciesMustBeDomainCol,
|
||||||
|
@@ -35,6 +35,7 @@ const (
|
|||||||
ExternalIDPSearchKeyUserID
|
ExternalIDPSearchKeyUserID
|
||||||
ExternalIDPSearchKeyIdpConfigID
|
ExternalIDPSearchKeyIdpConfigID
|
||||||
ExternalIDPSearchKeyResourceOwner
|
ExternalIDPSearchKeyResourceOwner
|
||||||
|
ExternalIDPSearchKeyInstanceID
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExternalIDPSearchQuery struct {
|
type ExternalIDPSearchQuery struct {
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/caos/zitadel/internal/domain"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NotifyUser struct {
|
type NotifyUser struct {
|
||||||
@@ -41,6 +42,7 @@ const (
|
|||||||
NotifyUserSearchKeyUnspecified NotifyUserSearchKey = iota
|
NotifyUserSearchKeyUnspecified NotifyUserSearchKey = iota
|
||||||
NotifyUserSearchKeyUserID
|
NotifyUserSearchKeyUserID
|
||||||
NotifyUserSearchKeyResourceOwner
|
NotifyUserSearchKeyResourceOwner
|
||||||
|
NotifyUserSearchKeyInstanceID
|
||||||
)
|
)
|
||||||
|
|
||||||
type NotifyUserSearchQuery struct {
|
type NotifyUserSearchQuery struct {
|
||||||
|
@@ -46,6 +46,7 @@ const (
|
|||||||
UserSessionSearchKeyUserID
|
UserSessionSearchKeyUserID
|
||||||
UserSessionSearchKeyState
|
UserSessionSearchKeyState
|
||||||
UserSessionSearchKeyResourceOwner
|
UserSessionSearchKeyResourceOwner
|
||||||
|
UserSessionSearchKeyInstanceID
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserSessionSearchQuery struct {
|
type UserSessionSearchQuery struct {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user