diff --git a/backend/v3/api/object/object.go b/backend/v3/api/object/object.go new file mode 100644 index 000000000..b6d7c500a --- /dev/null +++ b/backend/v3/api/object/object.go @@ -0,0 +1,55 @@ +package object + +import ( + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/zerrors" + v2_object "github.com/zitadel/zitadel/pkg/grpc/object/v2" + v2beta_object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" +) + +// TODO(IAM-Marco): Remove in V5 (see https://github.com/zitadel/zitadel/issues/10877) +func TextQueryMethodBetaToV2(txtMethod v2beta_object.TextQueryMethod) v2_object.TextQueryMethod { + switch txtMethod { + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE + case v2beta_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS: + fallthrough + default: + return v2_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS + } +} + +func TextQueryMethodToTextOperation(txtMethod v2_object.TextQueryMethod) (database.TextOperation, error) { + switch txtMethod { + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS: + return database.TextOperationContains, nil + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE: + return database.TextOperationContainsIgnoreCase, nil + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH: + return database.TextOperationEndsWith, nil + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE: + return database.TextOperationEndsWithIgnoreCase, nil + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE: + return database.TextOperationEqualIgnoreCase, nil + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH: + return database.TextOperationStartsWith, nil + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE: + return database.TextOperationStartsWithIgnoreCase, nil + case v2_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS: + return database.TextOperationEqual, nil + default: + return 0, zerrors.ThrowInvalidArgument(nil, "OBJ-iBRBVe", "invalid text query method") + } +} diff --git a/backend/v3/api/object/object_test.go b/backend/v3/api/object/object_test.go new file mode 100644 index 000000000..33cadc6c0 --- /dev/null +++ b/backend/v3/api/object/object_test.go @@ -0,0 +1,77 @@ +package object + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/zerrors" + v2_object "github.com/zitadel/zitadel/pkg/grpc/object/v2" +) + +func TestTextQueryMethodToTextOperation(t *testing.T) { + t.Parallel() + tt := []struct { + name string + queryOperation v2_object.TextQueryMethod + + expectedOperation database.TextOperation + expectedError error + }{ + { + name: "contains", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS, + expectedOperation: database.TextOperationContains, + }, + { + name: "contains ignore case", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE, + expectedOperation: database.TextOperationContainsIgnoreCase, + }, + { + name: "ends with", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH, + expectedOperation: database.TextOperationEndsWith, + }, + { + name: "ends with ignore case", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE, + expectedOperation: database.TextOperationEndsWithIgnoreCase, + }, + { + name: "equals", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS, + expectedOperation: database.TextOperationEqual, + }, + { + name: "equals ignore case", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE, + expectedOperation: database.TextOperationEqualIgnoreCase, + }, + { + name: "starts with", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH, + expectedOperation: database.TextOperationStartsWith, + }, + { + name: "starts with ignore case", + queryOperation: v2_object.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE, + expectedOperation: database.TextOperationStartsWithIgnoreCase, + }, + { + name: "unknown operation", + queryOperation: v2_object.TextQueryMethod(99), + expectedError: zerrors.ThrowInvalidArgument(nil, "OBJ-iBRBVe", "invalid text query method"), + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + got, err := TextQueryMethodToTextOperation(tc.queryOperation) + assert.Equal(t, tc.expectedError, err) + assert.Equal(t, tc.expectedOperation, got) + }) + } +} diff --git a/backend/v3/api/org/v2/convert/org.go b/backend/v3/api/org/v2/convert/org.go new file mode 100644 index 000000000..f9cd9f956 --- /dev/null +++ b/backend/v3/api/org/v2/convert/org.go @@ -0,0 +1,155 @@ +package convert + +import ( + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/zitadel/zitadel/backend/v3/api/object" + "github.com/zitadel/zitadel/backend/v3/domain" + grpc_object "github.com/zitadel/zitadel/pkg/grpc/object/v2" + v2_org "github.com/zitadel/zitadel/pkg/grpc/org/v2" + v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" +) + +/* + * GRPC Beta v2 to GRPC v2 + */ + +// TODO(IAM-Marco): Remove in V5 (see https://github.com/zitadel/zitadel/issues/10877) +func OrganizationBetaRequestToV2Request(in *v2beta_org.ListOrganizationsRequest) *v2_org.ListOrganizationsRequest { + return &v2_org.ListOrganizationsRequest{ + Query: &grpc_object.ListQuery{ + Offset: in.GetPagination().GetOffset(), + Limit: in.GetPagination().GetLimit(), + Asc: in.GetPagination().GetAsc(), + }, + SortingColumn: organizationSortingColumnBetaToV2(in.GetSortingColumn()), + Queries: organizationQueriesBetaToV2(in.GetFilter()), + } +} + +func organizationSortingColumnBetaToV2(sc v2beta_org.OrgFieldName) v2_org.OrganizationFieldName { + switch sc { + case v2beta_org.OrgFieldName_ORG_FIELD_NAME_NAME: + return v2_org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME + case v2beta_org.OrgFieldName_ORG_FIELD_NAME_CREATION_DATE, v2beta_org.OrgFieldName_ORG_FIELD_NAME_UNSPECIFIED: + fallthrough + default: + return v2_org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_UNSPECIFIED + } +} + +func organizationQueriesBetaToV2(queries []*v2beta_org.OrganizationSearchFilter) []*v2_org.SearchQuery { + toReturn := make([]*v2_org.SearchQuery, len(queries)) + + for i, query := range queries { + toReturn[i] = organizationQueryBetaToV2(query) + } + + return toReturn +} + +func organizationQueryBetaToV2(query *v2beta_org.OrganizationSearchFilter) *v2_org.SearchQuery { + toReturn := &v2_org.SearchQuery{} + + switch assertedType := query.GetFilter().(type) { + case *v2beta_org.OrganizationSearchFilter_DomainFilter: + toReturn.Query = &v2_org.SearchQuery_DomainQuery{ + DomainQuery: &v2_org.OrganizationDomainQuery{ + Domain: assertedType.DomainFilter.GetDomain(), + Method: object.TextQueryMethodBetaToV2(assertedType.DomainFilter.GetMethod()), + }, + } + + case *v2beta_org.OrganizationSearchFilter_IdFilter: + toReturn.Query = &v2_org.SearchQuery_IdQuery{ + IdQuery: &v2_org.OrganizationIDQuery{ + Id: assertedType.IdFilter.GetId(), + }, + } + case *v2beta_org.OrganizationSearchFilter_NameFilter: + toReturn.Query = &v2_org.SearchQuery_NameQuery{ + NameQuery: &v2_org.OrganizationNameQuery{ + Name: assertedType.NameFilter.GetName(), + Method: object.TextQueryMethodBetaToV2(assertedType.NameFilter.GetMethod()), + }, + } + case *v2beta_org.OrganizationSearchFilter_StateFilter: + toReturn.Query = &v2_org.SearchQuery_StateQuery{ + StateQuery: &v2_org.OrganizationStateQuery{ + State: organizationStateBetaToV2(assertedType.StateFilter.GetState()), + }, + } + default: + return toReturn + } + return toReturn +} + +func organizationStateBetaToV2(in v2beta_org.OrgState) v2_org.OrganizationState { + switch in { + case v2beta_org.OrgState_ORG_STATE_ACTIVE: + return v2_org.OrganizationState_ORGANIZATION_STATE_ACTIVE + case v2beta_org.OrgState_ORG_STATE_INACTIVE: + return v2_org.OrganizationState_ORGANIZATION_STATE_INACTIVE + case v2beta_org.OrgState_ORG_STATE_REMOVED: + return v2_org.OrganizationState_ORGANIZATION_STATE_REMOVED + case v2beta_org.OrgState_ORG_STATE_UNSPECIFIED: + fallthrough + default: + return v2_org.OrganizationState_ORGANIZATION_STATE_UNSPECIFIED + } +} + +/* + * Domain Model to GRPC v2 + */ + +func DomainOrganizationListModelToGRPCResponse(orgs []*domain.Organization) []*v2_org.Organization { + toReturn := make([]*v2_org.Organization, len(orgs)) + + for i, org := range orgs { + toReturn[i] = domainOrganizationModelToGRPCResponse(org) + } + + return toReturn +} + +func domainOrganizationModelToGRPCResponse(org *domain.Organization) *v2_org.Organization { + return &v2_org.Organization{ + Id: org.ID, + Details: &grpc_object.Details{ + ChangeDate: timestamppb.New(org.UpdatedAt), + CreationDate: timestamppb.New(org.CreatedAt), + }, + State: v2_org.OrganizationState(org.State), + Name: org.Name, + PrimaryDomain: org.PrimaryDomain(), + } +} + +/* + * Domain Model to GRPC v2 beta + */ + +// TODO(IAM-Marco): Remove in V5 (see https://github.com/zitadel/zitadel/issues/10877) +func DomainOrganizationListModelToGRPCBetaResponse(orgs []*domain.Organization) []*v2beta_org.Organization { + toReturn := make([]*v2beta_org.Organization, len(orgs)) + + for i, org := range orgs { + toReturn[i] = domainOrganizationModelToGRPCBetaResponse(org) + } + + return toReturn +} + +// TODO(IAM-Marco): Remove in V5 (see https://github.com/zitadel/zitadel/issues/10877) +func domainOrganizationModelToGRPCBetaResponse(org *domain.Organization) *v2beta_org.Organization { + return &v2beta_org.Organization{ + Id: org.ID, + ChangedDate: timestamppb.New(org.UpdatedAt), + CreationDate: timestamppb.New(org.CreatedAt), + State: v2beta_org.OrgState(org.State), + Name: org.Name, + PrimaryDomain: org.PrimaryDomain(), + } +} diff --git a/backend/v3/api/org/v2/convert/org_test.go b/backend/v3/api/org/v2/convert/org_test.go new file mode 100644 index 000000000..483c59054 --- /dev/null +++ b/backend/v3/api/org/v2/convert/org_test.go @@ -0,0 +1,89 @@ +package convert + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/zitadel/zitadel/backend/v3/domain" + "github.com/zitadel/zitadel/pkg/grpc/object/v2" + "github.com/zitadel/zitadel/pkg/grpc/org/v2" +) + +func TestDomainOrganizationListModelToGRPCResponse(t *testing.T) { + t.Parallel() + now := time.Now().UTC() + yesterday := now.AddDate(0, 0, -1) + + tt := []struct { + name string + orgs []*domain.Organization + want []*org.Organization + }{ + { + name: "empty result", + orgs: nil, + want: []*org.Organization{}, + }, + { + name: "multiple organizations", + orgs: []*domain.Organization{ + { + ID: "org-1", + Name: "org 1", + State: domain.OrgStateActive, + CreatedAt: yesterday, + UpdatedAt: now, + Domains: []*domain.OrganizationDomain{ + {Domain: "wrong selected domain"}, + {Domain: "domain.example.com", IsPrimary: true}, + }, + }, + { + ID: "org-2", + Name: "org 2", + State: domain.OrgStateInactive, + CreatedAt: yesterday, + UpdatedAt: now, + Domains: []*domain.OrganizationDomain{ + {Domain: "wrong selected domain 2"}, + {Domain: "domain2.example.com", IsPrimary: true}, + }, + }, + }, + want: []*org.Organization{ + { + Id: "org-1", + Name: "org 1", + State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE, + Details: &object.Details{ + ChangeDate: timestamppb.New(now), + CreationDate: timestamppb.New(yesterday), + }, + PrimaryDomain: "domain.example.com", + }, + { + Id: "org-2", + Name: "org 2", + State: org.OrganizationState_ORGANIZATION_STATE_INACTIVE, + Details: &object.Details{ + ChangeDate: timestamppb.New(now), + CreationDate: timestamppb.New(yesterday), + }, + PrimaryDomain: "domain2.example.com", + }, + }, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + got := DomainOrganizationListModelToGRPCResponse(tc.orgs) + assert.Equal(t, tc.want, got) + }) + } +} diff --git a/backend/v3/api/org/v2/org.go b/backend/v3/api/org/v2/org.go index 601846848..7665e3297 100644 --- a/backend/v3/api/org/v2/org.go +++ b/backend/v3/api/org/v2/org.go @@ -1,5 +1,22 @@ package orgv2 +import ( + "context" + "errors" + + "connectrpc.com/connect" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/zitadel/zitadel/backend/v3/api/org/v2/convert" + "github.com/zitadel/zitadel/backend/v3/domain" + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/repository" + filter "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta" + "github.com/zitadel/zitadel/pkg/grpc/object/v2" + v2_org "github.com/zitadel/zitadel/pkg/grpc/org/v2" + v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" +) + // import ( // "context" @@ -31,3 +48,137 @@ package orgv2 // } // return cmds // } + +func UpdateOrganization(ctx context.Context, request *connect.Request[v2beta_org.UpdateOrganizationRequest]) (*connect.Response[v2beta_org.UpdateOrganizationResponse], error) { + orgUpdateCmd := domain.NewUpdateOrgCommand(request.Msg.GetId(), request.Msg.GetName()) + + // TODO(IAM-Marco) Finish implementation in https://github.com/zitadel/zitadel/issues/10447 + domainAddCmd := domain.NewAddOrgDomainCommand(request.Msg.GetId(), request.Msg.GetName()) + domainSetPrimaryCmd := domain.NewSetPrimaryOrgDomainCommand(request.Msg.GetId(), request.Msg.GetName()) + domainRemoveCmd := domain.NewRemoveOrgDomainCommand(request.Msg.GetId(), orgUpdateCmd.OldDomainName, orgUpdateCmd.IsOldDomainVerified) + + batchCmd := domain.BatchExecutors(orgUpdateCmd, domainAddCmd, domainSetPrimaryCmd, domainRemoveCmd) + + err := domain.Invoke(ctx, batchCmd, domain.WithOrganizationRepo(repository.OrganizationRepository())) + if err != nil { + return nil, err + } + + return &connect.Response[v2beta_org.UpdateOrganizationResponse]{ + Msg: &v2beta_org.UpdateOrganizationResponse{ + // TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Update() + // returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881 + ChangeDate: timestamppb.Now(), + }, + }, nil +} + +func ListOrganizations(ctx context.Context, request *connect.Request[v2_org.ListOrganizationsRequest]) (*connect.Response[v2_org.ListOrganizationsResponse], error) { + orgListQuery := domain.NewListOrgsQuery(request.Msg) + + err := domain.Invoke(ctx, orgListQuery, + domain.WithOrganizationRepo(repository.OrganizationRepository()), + domain.WithOrganizationDomainRepo(repository.OrganizationDomainRepository()), + ) + if err != nil { + return nil, err + } + + orgs := convert.DomainOrganizationListModelToGRPCResponse(orgListQuery.Result()) + return &connect.Response[v2_org.ListOrganizationsResponse]{ + Msg: &v2_org.ListOrganizationsResponse{ + Result: orgs, + Details: &object.ListDetails{ + // TODO(IAM-Marco): Return correct result once permissions are in place + TotalResult: uint64(len(orgs)), + }, + SortingColumn: request.Msg.GetSortingColumn(), + }, + }, nil +} + +// TODO(IAM-Marco): Remove in V5 (see https://github.com/zitadel/zitadel/issues/10877) +func ListOrganizationsBeta(ctx context.Context, request *connect.Request[v2beta_org.ListOrganizationsRequest]) (*connect.Response[v2beta_org.ListOrganizationsResponse], error) { + orgListQuery := domain.NewListOrgsQuery(convert.OrganizationBetaRequestToV2Request(request.Msg)) + + err := domain.Invoke(ctx, orgListQuery, + domain.WithOrganizationRepo(repository.OrganizationRepository()), + domain.WithOrganizationDomainRepo(repository.OrganizationDomainRepository()), + ) + if err != nil { + return nil, err + } + + orgs := convert.DomainOrganizationListModelToGRPCBetaResponse(orgListQuery.Result()) + return &connect.Response[v2beta_org.ListOrganizationsResponse]{ + Msg: &v2beta_org.ListOrganizationsResponse{ + Organizations: orgs, + Pagination: &filter.PaginationResponse{ + TotalResult: uint64(len(orgs)), + AppliedLimit: uint64(request.Msg.GetPagination().GetLimit()), + }, + }, + }, nil +} + +func DeleteOrganization(ctx context.Context, request *connect.Request[v2beta_org.DeleteOrganizationRequest]) (*connect.Response[v2beta_org.DeleteOrganizationResponse], error) { + orgDeleteCmd := domain.NewDeleteOrgCommand(request.Msg.GetId()) + + err := domain.Invoke(ctx, orgDeleteCmd, + domain.WithOrganizationRepo(repository.OrganizationRepository()), + domain.WithProjectRepo(repository.ProjectRepository()), + ) + if err != nil { + var notFoundError *database.NoRowFoundError + if errors.As(err, ¬FoundError) { + return connect.NewResponse(&v2beta_org.DeleteOrganizationResponse{}), nil + } + return nil, err + } + + return &connect.Response[v2beta_org.DeleteOrganizationResponse]{ + Msg: &v2beta_org.DeleteOrganizationResponse{ + // TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Delete() + // returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881 + DeletionDate: timestamppb.Now(), + }, + }, nil +} + +func DeactivateOrganization(ctx context.Context, request *connect.Request[v2beta_org.DeactivateOrganizationRequest]) (*connect.Response[v2beta_org.DeactivateOrganizationResponse], error) { + orgDeactivateCmd := domain.NewDeactivateOrgCommand(request.Msg.GetId()) + + err := domain.Invoke(ctx, orgDeactivateCmd, + domain.WithOrganizationRepo(repository.OrganizationRepository()), + ) + if err != nil { + return nil, err + } + + return &connect.Response[v2beta_org.DeactivateOrganizationResponse]{ + Msg: &v2beta_org.DeactivateOrganizationResponse{ + // TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Update() + // returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881 + ChangeDate: timestamppb.Now(), + }, + }, nil +} + +func ActivateOrganization(ctx context.Context, request *connect.Request[v2beta_org.ActivateOrganizationRequest]) (*connect.Response[v2beta_org.ActivateOrganizationResponse], error) { + orgActivateCmd := domain.NewActivateOrgCommand(request.Msg.GetId()) + + err := domain.Invoke(ctx, orgActivateCmd, + domain.WithOrganizationRepo(repository.OrganizationRepository()), + ) + if err != nil { + return nil, err + } + + return &connect.Response[v2beta_org.ActivateOrganizationResponse]{ + Msg: &v2beta_org.ActivateOrganizationResponse{ + // TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Update() + // returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881 + ChangeDate: timestamppb.Now(), + }, + }, nil +} diff --git a/backend/v3/domain/command.go b/backend/v3/domain/command.go deleted file mode 100644 index 8dd301f53..000000000 --- a/backend/v3/domain/command.go +++ /dev/null @@ -1,148 +0,0 @@ -package domain - -import ( - "context" - "fmt" - - "github.com/zitadel/zitadel/backend/v3/storage/database" - legacy_es "github.com/zitadel/zitadel/internal/eventstore" -) - -// Commander is all that is needed to implement the command pattern. -// It is the interface all manipulations need to implement. -// If possible it should also be used for queries. We will find out if this is possible in the future. -type Commander interface { - Execute(ctx context.Context, opts *CommandOpts) (err error) - // Events returns the events that should be pushed to the event store after the command is executed. - // If the command does not produce events, it should return nil or an empty slice. - Events(ctx context.Context) []legacy_es.Command - fmt.Stringer -} - -// Invoker is part of the command pattern. -// It is the interface that is used to execute commands. -type Invoker interface { - Invoke(ctx context.Context, command Commander, opts *CommandOpts) error -} - -// CommandOpts are passed to each command -// it provides common fields used by commands like the database client. -type CommandOpts struct { - DB database.QueryExecutor - Invoker Invoker - Permissions PermissionChecker -} - -type ensureTxOpts struct { - *database.TransactionOptions -} - -type EnsureTransactionOpt func(*ensureTxOpts) - -// EnsureTx ensures that the DB is a transaction. If it is not, it will start a new transaction. -// The returned close function will end the transaction. If the DB is already a transaction, the close function -// will do nothing because another [Commander] is already responsible for ending the transaction. -func (o *CommandOpts) EnsureTx(ctx context.Context, opts ...EnsureTransactionOpt) (close func(context.Context, error) error, err error) { - beginner, ok := o.DB.(database.Beginner) - if !ok { - // db is already a transaction - return func(_ context.Context, err error) error { - return err - }, nil - } - - txOpts := &ensureTxOpts{ - TransactionOptions: new(database.TransactionOptions), - } - for _, opt := range opts { - opt(txOpts) - } - - tx, err := beginner.Begin(ctx, txOpts.TransactionOptions) - if err != nil { - return nil, err - } - o.DB = tx - - return func(ctx context.Context, err error) error { - return tx.End(ctx, err) - }, nil -} - -// EnsureClient ensures that the o.DB is a client. If it is not, it will get a new client from the [database.Pool]. -// The returned close function will release the client. If the o.DB is already a client or transaction, the close function -// will do nothing because another [Commander] is already responsible for releasing the client. -func (o *CommandOpts) EnsureClient(ctx context.Context) (close func(_ context.Context) error, err error) { - pool, ok := o.DB.(database.Pool) - if !ok { - // o.DB is already a client - return func(_ context.Context) error { - return nil - }, nil - } - client, err := pool.Acquire(ctx) - if err != nil { - return nil, err - } - o.DB = client - return func(ctx context.Context) error { - return client.Release(ctx) - }, nil -} - -func (o *CommandOpts) Invoke(ctx context.Context, command Commander) error { - if o.Invoker == nil { - return command.Execute(ctx, o) - } - return o.Invoker.Invoke(ctx, command, o) -} - -func DefaultOpts(invoker Invoker) *CommandOpts { - if invoker == nil { - invoker = &noopInvoker{} - } - return &CommandOpts{ - DB: pool, - Invoker: invoker, - Permissions: &noopPermissionChecker{}, // prevent panics for now - } -} - -// commandBatch is a batch of commands. -// It uses the [Invoker] provided by the opts to execute each command. -type commandBatch struct { - Commands []Commander -} - -// Events implements Commander. -func (cmd *commandBatch) Events(ctx context.Context) []legacy_es.Command { - commands := make([]legacy_es.Command, 0, len(cmd.Commands)) - for _, c := range cmd.Commands { - if e := c.Events(ctx); len(e) > 0 { - commands = append(commands, e...) - } - } - return commands -} - -func BatchCommands(cmds ...Commander) *commandBatch { - return &commandBatch{ - Commands: cmds, - } -} - -// String implements [Commander]. -func (cmd *commandBatch) String() string { - return "commandBatch" -} - -func (b *commandBatch) Execute(ctx context.Context, opts *CommandOpts) (err error) { - for _, cmd := range b.Commands { - if err = opts.Invoke(ctx, cmd); err != nil { - return err - } - } - return nil -} - -var _ Commander = (*commandBatch)(nil) diff --git a/backend/v3/domain/defaults.go b/backend/v3/domain/defaults.go index c2e5678af..407e31025 100644 --- a/backend/v3/domain/defaults.go +++ b/backend/v3/domain/defaults.go @@ -18,11 +18,6 @@ var ( logger logging.Logger = *logging.NewLogger(slog.Default()) legacyEventstore eventstore.LegacyEventstore - // userRepo func(database.QueryExecutor) UserRepository - // instanceRepo func(database.QueryExecutor) InstanceRepository - // cryptoRepo func(database.QueryExecutor) CryptoRepository - // orgRepo func(database.QueryExecutor) OrgRepository - // instanceCache cache.Cache[instanceCacheIndex, string, *Instance] // orgCache cache.Cache[orgCacheIndex, string, *Org] @@ -55,10 +50,6 @@ func SetLegacyEventstore(es eventstore.LegacyEventstore) { // userRepo = repo // } -// func SetOrgRepository(repo func(database.QueryExecutor) OrgRepository) { -// orgRepo = repo -// } - // func SetInstanceRepository(repo func(database.QueryExecutor) InstanceRepository) { // instanceRepo = repo // } diff --git a/backend/v3/domain/domain_test.go b/backend/v3/domain/domain_test.go index 503d322a5..19769aae1 100644 --- a/backend/v3/domain/domain_test.go +++ b/backend/v3/domain/domain_test.go @@ -1,67 +1,12 @@ package domain_test -// import ( -// "context" -// "log/slog" -// "testing" +import ( + "os" + "testing" +) -// "github.com/stretchr/testify/assert" -// "github.com/stretchr/testify/require" -// "go.opentelemetry.io/otel" -// "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" -// sdktrace "go.opentelemetry.io/otel/sdk/trace" -// "go.uber.org/mock/gomock" - -// . "github.com/zitadel/zitadel/backend/v3/domain" -// "github.com/zitadel/zitadel/backend/v3/storage/database/dbmock" -// "github.com/zitadel/zitadel/backend/v3/storage/database/repository" -// "github.com/zitadel/zitadel/backend/v3/telemetry/logging" -// "github.com/zitadel/zitadel/backend/v3/telemetry/tracing" -// ) - -// These tests give an overview of how to use the domain package. -// func TestExample(t *testing.T) { -// t.Skip("skip example test because it is not a real test") -// ctx := context.Background() - -// ctrl := gomock.NewController(t) -// pool := dbmock.NewMockPool(ctrl) -// tx := dbmock.NewMockTransaction(ctrl) - -// pool.EXPECT().Begin(gomock.Any(), gomock.Any()).Return(tx, nil) -// tx.EXPECT().End(gomock.Any(), gomock.Any()).Return(nil) -// SetPool(pool) - -// exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint()) -// require.NoError(t, err) -// tracerProvider := sdktrace.NewTracerProvider( -// sdktrace.WithSyncer(exporter), -// ) -// otel.SetTracerProvider(tracerProvider) -// SetTracer(tracing.Tracer{Tracer: tracerProvider.Tracer("test")}) -// defer func() { assert.NoError(t, tracerProvider.Shutdown(ctx)) }() - -// SetLogger(logging.Logger{Logger: slog.Default()}) - -// SetUserRepository(repository.UserRepository) -// SetOrgRepository(repository.OrgRepository) -// // SetInstanceRepository(repository.Instance) -// // SetCryptoRepository(repository.Crypto) - -// t.Run("create org", func(t *testing.T) { -// org := NewAddOrgCommand("testorg", NewAddMemberCommand("testuser", "ORG_OWNER")) -// user := NewCreateHumanCommand("testuser") -// err := Invoke(ctx, BatchCommands(org, user)) -// assert.NoError(t, err) -// }) - -// t.Run("verified email", func(t *testing.T) { -// err := Invoke(ctx, NewSetEmailCommand("u1", "test@example.com", NewEmailVerifiedCommand("u1", true))) -// assert.NoError(t, err) -// }) - -// t.Run("unverified email", func(t *testing.T) { -// err := Invoke(ctx, NewSetEmailCommand("u2", "test2@example.com", NewEmailVerifiedCommand("u2", false))) -// assert.NoError(t, err) -// }) -// } +func TestMain(m *testing.M) { + os.Exit(func() int { + return m.Run() + }()) +} diff --git a/backend/v3/domain/errors.go b/backend/v3/domain/errors.go index cb1a192c8..77ed61312 100644 --- a/backend/v3/domain/errors.go +++ b/backend/v3/domain/errors.go @@ -27,3 +27,48 @@ func (e *wrongIDPTypeError) Is(target error) bool { _, ok := target.(*wrongIDPTypeError) return ok } + +type MultipleObjectsUpdatedError struct { + Msg string + Expected int64 + Actual int64 +} + +func NewMultipleObjectsUpdatedError(expected, actual int64) error { + return &MultipleObjectsUpdatedError{ + Expected: expected, + Actual: actual, + } +} + +func (err *MultipleObjectsUpdatedError) Error() string { + return fmt.Sprintf("Message=expecting %d row(s) updated, got %d", err.Expected, err.Actual) +} + +type UnexpectedQueryTypeError[T any] struct { + assertedType T +} + +func NewUnexpectedQueryTypeError[T any](assertedType T) error { + return &UnexpectedQueryTypeError[T]{ + assertedType: assertedType, + } +} + +func (u *UnexpectedQueryTypeError[T]) Error() string { + return fmt.Sprintf("Message=unexpected query type '%T'", u.assertedType) +} + +type UnexpectedTextQueryOperationError[T any] struct { + assertedType T +} + +func NewUnexpectedTextQueryOperationError[T any](assertedType T) error { + return &UnexpectedTextQueryOperationError[T]{ + assertedType: assertedType, + } +} + +func (u *UnexpectedTextQueryOperationError[T]) Error() string { + return fmt.Sprintf("Message=unexpected text query operation type '%T'", u.assertedType) +} diff --git a/backend/v3/domain/errors_test.go b/backend/v3/domain/errors_test.go new file mode 100644 index 000000000..e0bbe617e --- /dev/null +++ b/backend/v3/domain/errors_test.go @@ -0,0 +1,38 @@ +package domain + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUnexpectedQueryTypeError_Error(t *testing.T) { + tests := []struct { + name string + typeVal any + expected string + }{ + { + name: "string type", + typeVal: "test", + expected: "Message=unexpected query type 'string'", + }, + { + name: "int type", + typeVal: 42, + expected: "Message=unexpected query type 'int'", + }, + { + name: "struct type", + typeVal: struct{}{}, + expected: "Message=unexpected query type 'struct {}'", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := NewUnexpectedQueryTypeError(tt.typeVal) + assert.Equal(t, tt.expected, err.Error()) + }) + } +} diff --git a/backend/v3/domain/executor_batch.go b/backend/v3/domain/executor_batch.go new file mode 100644 index 000000000..101c8a1dd --- /dev/null +++ b/backend/v3/domain/executor_batch.go @@ -0,0 +1,41 @@ +package domain + +import ( + "context" + "fmt" + "strings" +) + +// batchExecutor is a batch of [Executor]s. +// It uses the [Invoker]s provided by the opts to execute each [Executor]. +// The [Executor] is sent to all [Invoker]s before moving to the next [Executor]. +type batchExecutor struct { + executors []Executor +} + +func BatchExecutors(executors ...Executor) *batchExecutor { + return &batchExecutor{ + executors: executors, + } +} + +// String implements [Executor]. +func (cmd *batchExecutor) String() string { + names := make([]string, len(cmd.executors)) + for i, c := range cmd.executors { + names[i] = c.String() + } + return fmt.Sprintf("commandBatch[%s]", strings.Join(names, ", ")) +} + +// Execute implements [Executor]. +func (b *batchExecutor) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + for _, cmd := range b.executors { + if err = opts.Invoke(ctx, cmd); err != nil { + return err + } + } + return nil +} + +var _ Executor = (*batchExecutor)(nil) diff --git a/backend/v3/domain/executor_batch_test.go b/backend/v3/domain/executor_batch_test.go new file mode 100644 index 000000000..57e76cc41 --- /dev/null +++ b/backend/v3/domain/executor_batch_test.go @@ -0,0 +1,45 @@ +package domain_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + domainmock "github.com/zitadel/zitadel/backend/v3/domain/mock" +) + +func TestBatchExecutors(t *testing.T) { + // Given + mockCtrl := gomock.NewController(t) + mockCmd1 := domainmock.NewMockCommander(mockCtrl) + mockCmd2 := domainmock.NewMockCommander(mockCtrl) + mockCmd3 := domainmock.NewMockCommander(mockCtrl) + + mockCmd1.EXPECT().String().Return("cmd1").AnyTimes() + mockCmd2.EXPECT().String().Return("cmd2").AnyTimes() + mockCmd3.EXPECT().String().Return("cmd3").AnyTimes() + + gomock.InOrder( + mockCmd1.EXPECT().Validate(gomock.Any(), gomock.Any()).Times(1), + mockCmd1.EXPECT().Execute(gomock.Any(), gomock.Any()).Times(1), + mockCmd1.EXPECT().Events(gomock.Any(), gomock.Any()).Times(1), + mockCmd2.EXPECT().Validate(gomock.Any(), gomock.Any()).Times(1), + mockCmd2.EXPECT().Execute(gomock.Any(), gomock.Any()).Times(1), + mockCmd2.EXPECT().Events(gomock.Any(), gomock.Any()).Times(1), + mockCmd3.EXPECT().Validate(gomock.Any(), gomock.Any()).Times(1), + mockCmd3.EXPECT().Execute(gomock.Any(), gomock.Any()).Times(1), + mockCmd3.EXPECT().Events(gomock.Any(), gomock.Any()).Times(1), + ) + + batcher := domain.BatchExecutors(mockCmd1, mockCmd2, mockCmd3) + + // Test + err := domain.Invoke(context.Background(), batcher) + + // Verify + require.NoError(t, err) + require.True(t, mockCtrl.Satisfied()) +} diff --git a/backend/v3/domain/invoke.go b/backend/v3/domain/invoke.go index 4567ec30e..4163f23bd 100644 --- a/backend/v3/domain/invoke.go +++ b/backend/v3/domain/invoke.go @@ -3,157 +3,59 @@ package domain import ( "context" "fmt" - - "github.com/zitadel/zitadel/backend/v3/storage/eventstore" - legacy_es "github.com/zitadel/zitadel/internal/eventstore" ) +//go:generate mockgen -typed -package domainmock -destination ./mock/executor.mock.go . Executor +type Executor interface { + Execute(ctx context.Context, opts *InvokeOpts) (err error) + fmt.Stringer +} + +// Commander is all that is needed to implement the command pattern. +// It is the interface all manipulations need to implement. +// If possible it should also be used for queries. We will find out if this is possible in the future. +// +//go:generate mockgen -typed -package domainmock -destination ./mock/commander.mock.go . Commander +type Commander interface { + Validator + EventProducer + Executor +} + +// Querier used to query data. +// +//go:generate mockgen -typed -package domainmock -destination ./mock/querier.mock.go . Querier +type Querier[T any] interface { + Validator + Executor + // Result returns the result of the query. + // If `Execute` returns an error, the result is nil. + Result() T +} + // Invoke provides a way to execute commands within the domain package. // It uses a chain of responsibility pattern to handle the command execution. // The default chain includes logging, tracing, and event publishing. -// If you want to invoke multiple commands in a single transaction, you can use the [commandBatch]. -func Invoke(ctx context.Context, cmd Commander) error { - invoker := newEventStoreInvoker(newLoggingInvoker(newTraceInvoker(nil))) - opts := &CommandOpts{ - Invoker: invoker.collector, - DB: pool, +// If you want to invoke multiple commands in a single transaction, you can use the [batchExecutor]. +func Invoke(ctx context.Context, executor Executor, opts ...InvokeOpt) error { + invokeOpts := &InvokeOpts{ + Invoker: newEventStoreInvoker( + newLoggingInvoker( + newTraceInvoker( + newValidatorInvoker(nil), + ), + ), + ), + DB: pool, } - return invoker.Invoke(ctx, cmd, opts) -} - -// eventStoreInvoker checks if the [Commander].Events function returns any events. -// If it does, it collects the events and publishes them to the event store. -type eventStoreInvoker struct { - collector *eventCollector -} - -func newEventStoreInvoker(next Invoker) *eventStoreInvoker { - return &eventStoreInvoker{collector: &eventCollector{next: next}} -} - -func (i *eventStoreInvoker) Invoke(ctx context.Context, command Commander, opts *CommandOpts) (err error) { - err = i.collector.Invoke(ctx, command, opts) - if err != nil { - return err + for _, opt := range opts { + opt(invokeOpts) } - if len(i.collector.events) > 0 { - err = eventstore.Publish(ctx, legacyEventstore, opts.DB, i.collector.events...) - if err != nil { - return err - } - } - return nil + return invokeOpts.Invoke(ctx, executor) } -// eventCollector collects events from all commands. The [eventStoreInvoker] pushes the collected events after all commands are executed. -// The events are collected after the command got executed, the collector ensures that the command is executed in the same transaction as writing the events. -type eventCollector struct { - next Invoker - events []legacy_es.Command +// Invoker is part of the command pattern. +// It is the interface that is used to execute commands. +type Invoker interface { + Invoke(ctx context.Context, command Executor, opts *InvokeOpts) error } - -func (i *eventCollector) Invoke(ctx context.Context, command Commander, opts *CommandOpts) (err error) { - close, err := opts.EnsureTx(ctx) - if err != nil { - return err - } - defer func() { err = close(ctx, err) }() - - if i.next != nil { - err = i.next.Invoke(ctx, command, opts) - } else { - err = command.Execute(ctx, opts) - } - if err != nil { - return err - } - i.events = append(command.Events(ctx), i.events...) - - return -} - -// traceInvoker decorates each command with tracing. -type traceInvoker struct { - next Invoker -} - -func newTraceInvoker(next Invoker) *traceInvoker { - return &traceInvoker{next: next} -} - -func (i *traceInvoker) Invoke(ctx context.Context, command Commander, opts *CommandOpts) (err error) { - ctx, span := tracer.Start(ctx, fmt.Sprintf("%T", command)) - defer func() { - if err != nil { - span.RecordError(err) - } - span.End() - }() - - if i.next != nil { - return i.next.Invoke(ctx, command, opts) - } - return command.Execute(ctx, opts) -} - -// loggingInvoker decorates each command with logging. -// It is an example implementation and logs the command name at the beginning and success or failure after the command got executed. -type loggingInvoker struct { - next Invoker -} - -func newLoggingInvoker(next Invoker) *loggingInvoker { - return &loggingInvoker{next: next} -} - -func (i *loggingInvoker) Invoke(ctx context.Context, command Commander, opts *CommandOpts) (err error) { - logger.InfoContext(ctx, "Invoking command", "command", command.String()) - - if i.next != nil { - err = i.next.Invoke(ctx, command, opts) - } else { - err = command.Execute(ctx, opts) - } - - if err != nil { - logger.ErrorContext(ctx, "Command invocation failed", "command", command.String(), "error", err) - return err - } - logger.InfoContext(ctx, "Command invocation succeeded", "command", command.String()) - return nil -} - -type noopInvoker struct { - next Invoker -} - -func (i *noopInvoker) Invoke(ctx context.Context, command Commander, opts *CommandOpts) error { - if i.next != nil { - return i.next.Invoke(ctx, command, opts) - } - return command.Execute(ctx, opts) -} - -// cacheInvoker could be used in the future to do the caching. -// My goal would be to have two interfaces: -// - cacheSetter: which caches an object -// - cacheGetter: which gets an object from the cache, this should also skip the command execution -// type cacheInvoker struct { -// next Invoker -// } - -// type cacher interface { -// Cache(opts *CommandOpts) -// } - -// func (i *cacheInvoker) Invoke(ctx context.Context, command Commander, opts *CommandOpts) (err error) { -// if c, ok := command.(cacher); ok { -// c.Cache(opts) -// } -// if i.next != nil { -// err = i.next.Invoke(ctx, command, opts) -// } else { -// err = command.Execute(ctx, opts) -// } -// return err -// } diff --git a/backend/v3/domain/invoke_option.go b/backend/v3/domain/invoke_option.go new file mode 100644 index 000000000..6bc66844c --- /dev/null +++ b/backend/v3/domain/invoke_option.go @@ -0,0 +1,113 @@ +package domain + +import ( + "context" + + "github.com/zitadel/zitadel/backend/v3/storage/database" +) + +type InvokeOpt func(*InvokeOpts) + +func WithOrganizationRepo(repo OrganizationRepository) InvokeOpt { + return func(opts *InvokeOpts) { + opts.organizationRepo = repo + } +} + +func WithOrganizationDomainRepo(repo OrganizationDomainRepository) InvokeOpt { + return func(opts *InvokeOpts) { + opts.organizationDomainRepo = repo + } +} + +func WithProjectRepo(repo ProjectRepository) InvokeOpt { + return func(opts *InvokeOpts) { + opts.projectRepo = repo + } +} + +// InvokeOpts are passed to each command +// they provide common fields used by commands like the database client. +type InvokeOpts struct { + DB database.QueryExecutor + Invoker Invoker + Permissions PermissionChecker + organizationRepo OrganizationRepository + organizationDomainRepo OrganizationDomainRepository + projectRepo ProjectRepository +} + +type ensureTxOpts struct { + *database.TransactionOptions +} + +type EnsureTransactionOpt func(*ensureTxOpts) + +// EnsureTx ensures that the DB is a transaction. If it is not, it will start a new transaction. +// The returned close function will end the transaction. If the DB is already a transaction, the close function +// will be a noop because another [Executor] is already responsible for ending the transaction. +func (o *InvokeOpts) EnsureTx(ctx context.Context, opts ...EnsureTransactionOpt) (close func(context.Context, error) error, err error) { + beginner, ok := o.DB.(database.Beginner) + if !ok { + // db is already a transaction + return func(_ context.Context, err error) error { + return err + }, nil + } + + txOpts := &ensureTxOpts{ + TransactionOptions: new(database.TransactionOptions), + } + for _, opt := range opts { + opt(txOpts) + } + + tx, err := beginner.Begin(ctx, txOpts.TransactionOptions) + if err != nil { + return nil, err + } + o.DB = tx + + return func(ctx context.Context, err error) error { + return tx.End(ctx, err) + }, nil +} + +// EnsureClient ensures that the o.DB is a client. If it is not, it will get a new client from the [database.Pool]. +// The returned close function will release the client. If the o.DB is already a client or transaction, the close function +// will do nothing because another [Executor] is already responsible for releasing the client. +func (o *InvokeOpts) EnsureClient(ctx context.Context) (close func(_ context.Context) error, err error) { + pool, ok := o.DB.(database.Pool) + if !ok { + // o.DB is already a client + return func(_ context.Context) error { + return nil + }, nil + } + client, err := pool.Acquire(ctx) + if err != nil { + return nil, err + } + o.DB = client + return func(ctx context.Context) error { + return client.Release(ctx) + }, nil +} + +func (o *InvokeOpts) Invoke(ctx context.Context, executor Executor) error { + if o.Invoker == nil { + return executor.Execute(ctx, o) + } + return o.Invoker.Invoke(ctx, executor, o) +} + +func DefaultOpts(invoker Invoker) *InvokeOpts { + if invoker == nil { + invoker = &noopInvoker{} + } + return &InvokeOpts{ + DB: pool, + Invoker: invoker, + Permissions: &noopPermissionChecker{}, // prevent panics for now + } +} diff --git a/backend/v3/domain/invoke_test.go b/backend/v3/domain/invoke_test.go index b392e0478..b46585383 100644 --- a/backend/v3/domain/invoke_test.go +++ b/backend/v3/domain/invoke_test.go @@ -24,27 +24,32 @@ var _ eventstore.LegacyEventstore = (*testLegacyEventstore)(nil) type invokeTestCommand struct { events []legacy_es.Command - execute func(ctx context.Context, opts *CommandOpts) error + execute func(ctx context.Context, opts *InvokeOpts) error } -// Events implements Commander. -func (i *invokeTestCommand) Events(ctx context.Context) []legacy_es.Command { - return i.events +// Events implements [Commander]. +func (i *invokeTestCommand) Events(ctx context.Context, opts *InvokeOpts) ([]legacy_es.Command, error) { + return i.events, nil } -// Execute implements Commander. -func (i *invokeTestCommand) Execute(ctx context.Context, opts *CommandOpts) (err error) { +// Execute implements [Commander]. +func (i *invokeTestCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { if i.execute == nil { return nil } return i.execute(ctx, opts) } -// String implements Commander. +// String implements [Commander]. func (i *invokeTestCommand) String() string { return "invokeTestCommand" } +// Validate implements [Commander]. +func (i *invokeTestCommand) Validate(ctx context.Context, opts *InvokeOpts) (err error) { + return nil +} + var _ Commander = (*invokeTestCommand)(nil) type invokeTestEvent struct { @@ -125,7 +130,7 @@ func Test_eventCollector_Invoke(t *testing.T) { expectedErr: nil, command: &invokeTestCommand{ events: []legacy_es.Command{&invokeTestEvent{id: "1"}}, - execute: func(ctx context.Context, opts *CommandOpts) error { + execute: func(ctx context.Context, opts *InvokeOpts) error { return opts.Invoke(ctx, &invokeTestCommand{ events: []legacy_es.Command{&invokeTestEvent{id: "2"}}, }) @@ -133,15 +138,15 @@ func Test_eventCollector_Invoke(t *testing.T) { }, assertCollectedEvents: func(t *testing.T, events []legacy_es.Command) { require.Len(t, events, 2) - assert.Equal(t, "1", events[0].Aggregate().ID) - assert.Equal(t, "2", events[1].Aggregate().ID) + assert.Equal(t, "1", events[1].Aggregate().ID) + assert.Equal(t, "2", events[0].Aggregate().ID) }, }, { name: "only sub commands with events", expectedErr: nil, command: &invokeTestCommand{ - execute: func(ctx context.Context, opts *CommandOpts) error { + execute: func(ctx context.Context, opts *InvokeOpts) error { return opts.Invoke(ctx, &invokeTestCommand{ events: []legacy_es.Command{&invokeTestEvent{id: "2"}}, }) @@ -152,6 +157,27 @@ func Test_eventCollector_Invoke(t *testing.T) { assert.Equal(t, "2", events[0].Aggregate().ID) }, }, + { + name: "executor batch all commands", + expectedErr: nil, + command: &invokeTestCommand{ + execute: func(ctx context.Context, opts *InvokeOpts) error { + return opts.Invoke(ctx, BatchExecutors( + &invokeTestCommand{ + events: []legacy_es.Command{&invokeTestEvent{id: "2"}}, + }, + &invokeTestCommand{ + events: []legacy_es.Command{&invokeTestEvent{id: "3"}}, + }, + )) + }, + }, + assertCollectedEvents: func(t *testing.T, events []legacy_es.Command) { + require.Len(t, events, 2) + assert.Equal(t, "2", events[0].Aggregate().ID) + assert.Equal(t, "3", events[1].Aggregate().ID) + }, + }, } SetLegacyEventstore(new(testLegacyEventstore)) @@ -160,15 +186,13 @@ func Test_eventCollector_Invoke(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) - pool := dbmock.NewMockPool(ctrl) - tx := dbmock.NewMockTransaction(ctrl) tx.EXPECT().End(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() pool.EXPECT().Begin(gomock.Any(), gomock.Any()).Return(tx, nil).AnyTimes() i := newEventStoreInvoker(nil) - opts := CommandOpts{ + opts := InvokeOpts{ Invoker: i, DB: pool, } diff --git a/backend/v3/domain/invoker_event.go b/backend/v3/domain/invoker_event.go new file mode 100644 index 000000000..17c0d0b4c --- /dev/null +++ b/backend/v3/domain/invoker_event.go @@ -0,0 +1,106 @@ +package domain + +import ( + "context" + + "github.com/zitadel/zitadel/backend/v3/storage/eventstore" + legacy_es "github.com/zitadel/zitadel/internal/eventstore" +) + +// eventStoreInvoker checks if the [EventProducer].Events function returns any events. +// If it does, it collects the events and publishes them to the event store. +type eventStoreInvoker struct { + next Invoker + collector *eventCollector +} + +func newEventStoreInvoker(next Invoker) *eventStoreInvoker { + return &eventStoreInvoker{next: next} +} + +type EventProducer interface { + // Events returns the events that should be pushed to the event store after the command is executed. + // If the command does not produce events, it should `return nil, nil`. + Events(ctx context.Context, opts *InvokeOpts) ([]legacy_es.Command, error) +} + +func (i *eventStoreInvoker) Invoke(ctx context.Context, executor Executor, opts *InvokeOpts) (err error) { + if _, ok := executor.(EventProducer); !ok { + return i.execute(ctx, executor, opts) + } + + if i.collector != nil { + return i.collector.Invoke(ctx, executor, opts) + } + + close, err := opts.EnsureTx(ctx) + if err != nil { + return err + } + defer func() { err = close(ctx, err) }() + + i.collector = &eventCollector{next: i.next} + + if err = i.collector.Invoke(ctx, executor, opts); err != nil { + return err + } + + if len(i.collector.events) > 0 { + err = eventstore.Publish(ctx, legacyEventstore, opts.DB, i.collector.events...) + if err != nil { + return err + } + } + return nil +} + +func (i *eventStoreInvoker) execute(ctx context.Context, executor Executor, opts *InvokeOpts) error { + if i.next != nil { + return i.next.Invoke(ctx, executor, opts) + } + return executor.Execute(ctx, opts) +} + +// eventCollector collects events from all commands. The [eventStoreInvoker] pushes the collected events after all commands are executed. +// The events are collected after the command got executed, the collector ensures that the command is executed in the same transaction as writing the events. +type eventCollector struct { + next Invoker + events []legacy_es.Command + shouldPrepend bool +} + +func (i *eventCollector) Invoke(ctx context.Context, executor Executor, opts *InvokeOpts) (err error) { + command, ok := executor.(EventProducer) + if !ok { + if i.next != nil { + return i.next.Invoke(ctx, executor, opts) + } + return executor.Execute(ctx, opts) + } + + shouldPrepend := i.shouldPrepend + i.shouldPrepend = false + + if i.next != nil { + i.shouldPrepend = true + err = i.next.Invoke(ctx, executor, opts) + i.shouldPrepend = false + } else { + err = executor.Execute(ctx, opts) + } + if err != nil { + return err + } + collectedEvents, err := command.Events(ctx, opts) + if err != nil { + return err + } + + if shouldPrepend { + i.events = append(collectedEvents, i.events...) + } else { + i.events = append(i.events, collectedEvents...) + } + + return err +} diff --git a/backend/v3/domain/invoker_logging.go b/backend/v3/domain/invoker_logging.go new file mode 100644 index 000000000..8ce337ac5 --- /dev/null +++ b/backend/v3/domain/invoker_logging.go @@ -0,0 +1,34 @@ +package domain + +import ( + "context" + "time" +) + +// loggingInvoker decorates each command with logging. +// It is an example implementation and logs the command name at the beginning and success or failure after the command got executed. +type loggingInvoker struct { + next Invoker +} + +func newLoggingInvoker(next Invoker) *loggingInvoker { + return &loggingInvoker{next: next} +} + +func (i *loggingInvoker) Invoke(ctx context.Context, executor Executor, opts *InvokeOpts) (err error) { + start := time.Now() + logger.InfoContext(ctx, "invoking", "name", executor.String()) + + if i.next != nil { + err = i.next.Invoke(ctx, executor, opts) + } else { + err = executor.Execute(ctx, opts) + } + + if err != nil { + logger.ErrorContext(ctx, "invocation failed", "name", executor.String(), "error", err, "took", time.Since(start)) + return err + } + logger.InfoContext(ctx, "invocation succeeded", "name", executor.String(), "took", time.Since(start)) + return nil +} diff --git a/backend/v3/domain/invoker_noop.go b/backend/v3/domain/invoker_noop.go new file mode 100644 index 000000000..92935a515 --- /dev/null +++ b/backend/v3/domain/invoker_noop.go @@ -0,0 +1,14 @@ +package domain + +import "context" + +type noopInvoker struct { + next Invoker +} + +func (i *noopInvoker) Invoke(ctx context.Context, command Executor, opts *InvokeOpts) error { + if i.next != nil { + return i.next.Invoke(ctx, command, opts) + } + return command.Execute(ctx, opts) +} diff --git a/backend/v3/domain/invoker_tracing.go b/backend/v3/domain/invoker_tracing.go new file mode 100644 index 000000000..4cfced0ba --- /dev/null +++ b/backend/v3/domain/invoker_tracing.go @@ -0,0 +1,30 @@ +package domain + +import ( + "context" + "fmt" +) + +// traceInvoker decorates each command with tracing. +type traceInvoker struct { + next Invoker +} + +func newTraceInvoker(next Invoker) *traceInvoker { + return &traceInvoker{next: next} +} + +func (i *traceInvoker) Invoke(ctx context.Context, executor Executor, opts *InvokeOpts) (err error) { + ctx, span := tracer.Start(ctx, fmt.Sprintf("%T", executor)) + defer func() { + if err != nil { + span.RecordError(err) + } + span.End() + }() + + if i.next != nil { + return i.next.Invoke(ctx, executor, opts) + } + return executor.Execute(ctx, opts) +} diff --git a/backend/v3/domain/invoker_validation.go b/backend/v3/domain/invoker_validation.go new file mode 100644 index 000000000..6b601517a --- /dev/null +++ b/backend/v3/domain/invoker_validation.go @@ -0,0 +1,31 @@ +package domain + +import ( + "context" +) + +type validatorInvoker struct { + next Invoker +} + +func newValidatorInvoker(next Invoker) *validatorInvoker { + return &validatorInvoker{next: next} +} + +type Validator interface { + Validate(ctx context.Context, opts *InvokeOpts) (err error) +} + +func (i *validatorInvoker) Invoke(ctx context.Context, executor Executor, opts *InvokeOpts) error { + if validator, ok := executor.(Validator); ok { + if err := validator.Validate(ctx, opts); err != nil { + return err + } + } + + if i.next != nil { + return i.next.Invoke(ctx, executor, opts) + } + + return executor.Execute(ctx, opts) +} diff --git a/backend/v3/domain/mock/commander.mock.go b/backend/v3/domain/mock/commander.mock.go new file mode 100644 index 000000000..dc5d2b360 --- /dev/null +++ b/backend/v3/domain/mock/commander.mock.go @@ -0,0 +1,196 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/zitadel/zitadel/backend/v3/domain (interfaces: Commander) +// +// Generated by this command: +// +// mockgen -typed -package domainmock -destination ./mock/commander.mock.go . Commander +// + +// Package domainmock is a generated GoMock package. +package domainmock + +import ( + context "context" + reflect "reflect" + + domain "github.com/zitadel/zitadel/backend/v3/domain" + eventstore "github.com/zitadel/zitadel/internal/eventstore" + gomock "go.uber.org/mock/gomock" +) + +// MockCommander is a mock of Commander interface. +type MockCommander struct { + ctrl *gomock.Controller + recorder *MockCommanderMockRecorder + isgomock struct{} +} + +// MockCommanderMockRecorder is the mock recorder for MockCommander. +type MockCommanderMockRecorder struct { + mock *MockCommander +} + +// NewMockCommander creates a new mock instance. +func NewMockCommander(ctrl *gomock.Controller) *MockCommander { + mock := &MockCommander{ctrl: ctrl} + mock.recorder = &MockCommanderMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCommander) EXPECT() *MockCommanderMockRecorder { + return m.recorder +} + +// Events mocks base method. +func (m *MockCommander) Events(ctx context.Context, opts *domain.InvokeOpts) ([]eventstore.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Events", ctx, opts) + ret0, _ := ret[0].([]eventstore.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Events indicates an expected call of Events. +func (mr *MockCommanderMockRecorder) Events(ctx, opts any) *MockCommanderEventsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Events", reflect.TypeOf((*MockCommander)(nil).Events), ctx, opts) + return &MockCommanderEventsCall{Call: call} +} + +// MockCommanderEventsCall wrap *gomock.Call +type MockCommanderEventsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockCommanderEventsCall) Return(arg0 []eventstore.Command, arg1 error) *MockCommanderEventsCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockCommanderEventsCall) Do(f func(context.Context, *domain.InvokeOpts) ([]eventstore.Command, error)) *MockCommanderEventsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockCommanderEventsCall) DoAndReturn(f func(context.Context, *domain.InvokeOpts) ([]eventstore.Command, error)) *MockCommanderEventsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Execute mocks base method. +func (m *MockCommander) Execute(ctx context.Context, opts *domain.InvokeOpts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Execute", ctx, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// Execute indicates an expected call of Execute. +func (mr *MockCommanderMockRecorder) Execute(ctx, opts any) *MockCommanderExecuteCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockCommander)(nil).Execute), ctx, opts) + return &MockCommanderExecuteCall{Call: call} +} + +// MockCommanderExecuteCall wrap *gomock.Call +type MockCommanderExecuteCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockCommanderExecuteCall) Return(err error) *MockCommanderExecuteCall { + c.Call = c.Call.Return(err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockCommanderExecuteCall) Do(f func(context.Context, *domain.InvokeOpts) error) *MockCommanderExecuteCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockCommanderExecuteCall) DoAndReturn(f func(context.Context, *domain.InvokeOpts) error) *MockCommanderExecuteCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// String mocks base method. +func (m *MockCommander) String() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "String") + ret0, _ := ret[0].(string) + return ret0 +} + +// String indicates an expected call of String. +func (mr *MockCommanderMockRecorder) String() *MockCommanderStringCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockCommander)(nil).String)) + return &MockCommanderStringCall{Call: call} +} + +// MockCommanderStringCall wrap *gomock.Call +type MockCommanderStringCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockCommanderStringCall) Return(arg0 string) *MockCommanderStringCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockCommanderStringCall) Do(f func() string) *MockCommanderStringCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockCommanderStringCall) DoAndReturn(f func() string) *MockCommanderStringCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Validate mocks base method. +func (m *MockCommander) Validate(ctx context.Context, opts *domain.InvokeOpts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validate", ctx, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// Validate indicates an expected call of Validate. +func (mr *MockCommanderMockRecorder) Validate(ctx, opts any) *MockCommanderValidateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockCommander)(nil).Validate), ctx, opts) + return &MockCommanderValidateCall{Call: call} +} + +// MockCommanderValidateCall wrap *gomock.Call +type MockCommanderValidateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockCommanderValidateCall) Return(err error) *MockCommanderValidateCall { + c.Call = c.Call.Return(err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockCommanderValidateCall) Do(f func(context.Context, *domain.InvokeOpts) error) *MockCommanderValidateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockCommanderValidateCall) DoAndReturn(f func(context.Context, *domain.InvokeOpts) error) *MockCommanderValidateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/backend/v3/domain/mock/org.mock.go b/backend/v3/domain/mock/org.mock.go new file mode 100644 index 000000000..363c04eed --- /dev/null +++ b/backend/v3/domain/mock/org.mock.go @@ -0,0 +1,860 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/zitadel/zitadel/backend/v3/domain (interfaces: OrganizationRepository) +// +// Generated by this command: +// +// mockgen -typed -package domainmock -destination ./mock/org.mock.go . OrganizationRepository +// + +// Package domainmock is a generated GoMock package. +package domainmock + +import ( + context "context" + reflect "reflect" + + domain "github.com/zitadel/zitadel/backend/v3/domain" + database "github.com/zitadel/zitadel/backend/v3/storage/database" + gomock "go.uber.org/mock/gomock" +) + +// MockOrganizationRepository is a mock of OrganizationRepository interface. +type MockOrganizationRepository struct { + ctrl *gomock.Controller + recorder *MockOrganizationRepositoryMockRecorder + isgomock struct{} +} + +// MockOrganizationRepositoryMockRecorder is the mock recorder for MockOrganizationRepository. +type MockOrganizationRepositoryMockRecorder struct { + mock *MockOrganizationRepository +} + +// NewMockOrganizationRepository creates a new mock instance. +func NewMockOrganizationRepository(ctrl *gomock.Controller) *MockOrganizationRepository { + mock := &MockOrganizationRepository{ctrl: ctrl} + mock.recorder = &MockOrganizationRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockOrganizationRepository) EXPECT() *MockOrganizationRepositoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockOrganizationRepository) Create(ctx context.Context, client database.QueryExecutor, org *domain.Organization) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, client, org) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockOrganizationRepositoryMockRecorder) Create(ctx, client, org any) *MockOrganizationRepositoryCreateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockOrganizationRepository)(nil).Create), ctx, client, org) + return &MockOrganizationRepositoryCreateCall{Call: call} +} + +// MockOrganizationRepositoryCreateCall wrap *gomock.Call +type MockOrganizationRepositoryCreateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryCreateCall) Return(arg0 error) *MockOrganizationRepositoryCreateCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryCreateCall) Do(f func(context.Context, database.QueryExecutor, *domain.Organization) error) *MockOrganizationRepositoryCreateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryCreateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, *domain.Organization) error) *MockOrganizationRepositoryCreateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CreatedAtColumn mocks base method. +func (m *MockOrganizationRepository) CreatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// CreatedAtColumn indicates an expected call of CreatedAtColumn. +func (mr *MockOrganizationRepositoryMockRecorder) CreatedAtColumn() *MockOrganizationRepositoryCreatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtColumn", reflect.TypeOf((*MockOrganizationRepository)(nil).CreatedAtColumn)) + return &MockOrganizationRepositoryCreatedAtColumnCall{Call: call} +} + +// MockOrganizationRepositoryCreatedAtColumnCall wrap *gomock.Call +type MockOrganizationRepositoryCreatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryCreatedAtColumnCall) Return(arg0 database.Column) *MockOrganizationRepositoryCreatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryCreatedAtColumnCall) Do(f func() database.Column) *MockOrganizationRepositoryCreatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryCreatedAtColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationRepositoryCreatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Delete mocks base method. +func (m *MockOrganizationRepository) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, client, condition) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockOrganizationRepositoryMockRecorder) Delete(ctx, client, condition any) *MockOrganizationRepositoryDeleteCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockOrganizationRepository)(nil).Delete), ctx, client, condition) + return &MockOrganizationRepositoryDeleteCall{Call: call} +} + +// MockOrganizationRepositoryDeleteCall wrap *gomock.Call +type MockOrganizationRepositoryDeleteCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryDeleteCall) Return(arg0 int64, arg1 error) *MockOrganizationRepositoryDeleteCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryDeleteCall) Do(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockOrganizationRepositoryDeleteCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryDeleteCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockOrganizationRepositoryDeleteCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ExistsDomain mocks base method. +func (m *MockOrganizationRepository) ExistsDomain(cond database.Condition) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExistsDomain", cond) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// ExistsDomain indicates an expected call of ExistsDomain. +func (mr *MockOrganizationRepositoryMockRecorder) ExistsDomain(cond any) *MockOrganizationRepositoryExistsDomainCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsDomain", reflect.TypeOf((*MockOrganizationRepository)(nil).ExistsDomain), cond) + return &MockOrganizationRepositoryExistsDomainCall{Call: call} +} + +// MockOrganizationRepositoryExistsDomainCall wrap *gomock.Call +type MockOrganizationRepositoryExistsDomainCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryExistsDomainCall) Return(arg0 database.Condition) *MockOrganizationRepositoryExistsDomainCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryExistsDomainCall) Do(f func(database.Condition) database.Condition) *MockOrganizationRepositoryExistsDomainCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryExistsDomainCall) DoAndReturn(f func(database.Condition) database.Condition) *MockOrganizationRepositoryExistsDomainCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ExistsMetadata mocks base method. +func (m *MockOrganizationRepository) ExistsMetadata(cond database.Condition) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExistsMetadata", cond) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// ExistsMetadata indicates an expected call of ExistsMetadata. +func (mr *MockOrganizationRepositoryMockRecorder) ExistsMetadata(cond any) *MockOrganizationRepositoryExistsMetadataCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsMetadata", reflect.TypeOf((*MockOrganizationRepository)(nil).ExistsMetadata), cond) + return &MockOrganizationRepositoryExistsMetadataCall{Call: call} +} + +// MockOrganizationRepositoryExistsMetadataCall wrap *gomock.Call +type MockOrganizationRepositoryExistsMetadataCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryExistsMetadataCall) Return(arg0 database.Condition) *MockOrganizationRepositoryExistsMetadataCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryExistsMetadataCall) Do(f func(database.Condition) database.Condition) *MockOrganizationRepositoryExistsMetadataCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryExistsMetadataCall) DoAndReturn(f func(database.Condition) database.Condition) *MockOrganizationRepositoryExistsMetadataCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Get mocks base method. +func (m *MockOrganizationRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Organization, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Get", varargs...) + ret0, _ := ret[0].(*domain.Organization) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockOrganizationRepositoryMockRecorder) Get(ctx, client any, opts ...any) *MockOrganizationRepositoryGetCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockOrganizationRepository)(nil).Get), varargs...) + return &MockOrganizationRepositoryGetCall{Call: call} +} + +// MockOrganizationRepositoryGetCall wrap *gomock.Call +type MockOrganizationRepositoryGetCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryGetCall) Return(arg0 *domain.Organization, arg1 error) *MockOrganizationRepositoryGetCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryGetCall) Do(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.Organization, error)) *MockOrganizationRepositoryGetCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryGetCall) DoAndReturn(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.Organization, error)) *MockOrganizationRepositoryGetCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDColumn mocks base method. +func (m *MockOrganizationRepository) IDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDColumn indicates an expected call of IDColumn. +func (mr *MockOrganizationRepositoryMockRecorder) IDColumn() *MockOrganizationRepositoryIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDColumn", reflect.TypeOf((*MockOrganizationRepository)(nil).IDColumn)) + return &MockOrganizationRepositoryIDColumnCall{Call: call} +} + +// MockOrganizationRepositoryIDColumnCall wrap *gomock.Call +type MockOrganizationRepositoryIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryIDColumnCall) Return(arg0 database.Column) *MockOrganizationRepositoryIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryIDColumnCall) Do(f func() database.Column) *MockOrganizationRepositoryIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryIDColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationRepositoryIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDCondition mocks base method. +func (m *MockOrganizationRepository) IDCondition(instanceID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDCondition", instanceID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IDCondition indicates an expected call of IDCondition. +func (mr *MockOrganizationRepositoryMockRecorder) IDCondition(instanceID any) *MockOrganizationRepositoryIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDCondition", reflect.TypeOf((*MockOrganizationRepository)(nil).IDCondition), instanceID) + return &MockOrganizationRepositoryIDConditionCall{Call: call} +} + +// MockOrganizationRepositoryIDConditionCall wrap *gomock.Call +type MockOrganizationRepositoryIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryIDConditionCall) Return(arg0 database.Condition) *MockOrganizationRepositoryIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryIDConditionCall) Do(f func(string) database.Condition) *MockOrganizationRepositoryIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockOrganizationRepositoryIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDColumn mocks base method. +func (m *MockOrganizationRepository) InstanceIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// InstanceIDColumn indicates an expected call of InstanceIDColumn. +func (mr *MockOrganizationRepositoryMockRecorder) InstanceIDColumn() *MockOrganizationRepositoryInstanceIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDColumn", reflect.TypeOf((*MockOrganizationRepository)(nil).InstanceIDColumn)) + return &MockOrganizationRepositoryInstanceIDColumnCall{Call: call} +} + +// MockOrganizationRepositoryInstanceIDColumnCall wrap *gomock.Call +type MockOrganizationRepositoryInstanceIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryInstanceIDColumnCall) Return(arg0 database.Column) *MockOrganizationRepositoryInstanceIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryInstanceIDColumnCall) Do(f func() database.Column) *MockOrganizationRepositoryInstanceIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryInstanceIDColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationRepositoryInstanceIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDCondition mocks base method. +func (m *MockOrganizationRepository) InstanceIDCondition(instanceID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDCondition", instanceID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// InstanceIDCondition indicates an expected call of InstanceIDCondition. +func (mr *MockOrganizationRepositoryMockRecorder) InstanceIDCondition(instanceID any) *MockOrganizationRepositoryInstanceIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDCondition", reflect.TypeOf((*MockOrganizationRepository)(nil).InstanceIDCondition), instanceID) + return &MockOrganizationRepositoryInstanceIDConditionCall{Call: call} +} + +// MockOrganizationRepositoryInstanceIDConditionCall wrap *gomock.Call +type MockOrganizationRepositoryInstanceIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryInstanceIDConditionCall) Return(arg0 database.Condition) *MockOrganizationRepositoryInstanceIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryInstanceIDConditionCall) Do(f func(string) database.Condition) *MockOrganizationRepositoryInstanceIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryInstanceIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockOrganizationRepositoryInstanceIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// List mocks base method. +func (m *MockOrganizationRepository) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.Organization, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "List", varargs...) + ret0, _ := ret[0].([]*domain.Organization) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockOrganizationRepositoryMockRecorder) List(ctx, client any, opts ...any) *MockOrganizationRepositoryListCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockOrganizationRepository)(nil).List), varargs...) + return &MockOrganizationRepositoryListCall{Call: call} +} + +// MockOrganizationRepositoryListCall wrap *gomock.Call +type MockOrganizationRepositoryListCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryListCall) Return(arg0 []*domain.Organization, arg1 error) *MockOrganizationRepositoryListCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryListCall) Do(f func(context.Context, database.QueryExecutor, ...database.QueryOption) ([]*domain.Organization, error)) *MockOrganizationRepositoryListCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryListCall) DoAndReturn(f func(context.Context, database.QueryExecutor, ...database.QueryOption) ([]*domain.Organization, error)) *MockOrganizationRepositoryListCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// LoadDomains mocks base method. +func (m *MockOrganizationRepository) LoadDomains() domain.OrganizationRepository { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadDomains") + ret0, _ := ret[0].(domain.OrganizationRepository) + return ret0 +} + +// LoadDomains indicates an expected call of LoadDomains. +func (mr *MockOrganizationRepositoryMockRecorder) LoadDomains() *MockOrganizationRepositoryLoadDomainsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadDomains", reflect.TypeOf((*MockOrganizationRepository)(nil).LoadDomains)) + return &MockOrganizationRepositoryLoadDomainsCall{Call: call} +} + +// MockOrganizationRepositoryLoadDomainsCall wrap *gomock.Call +type MockOrganizationRepositoryLoadDomainsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryLoadDomainsCall) Return(arg0 domain.OrganizationRepository) *MockOrganizationRepositoryLoadDomainsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryLoadDomainsCall) Do(f func() domain.OrganizationRepository) *MockOrganizationRepositoryLoadDomainsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryLoadDomainsCall) DoAndReturn(f func() domain.OrganizationRepository) *MockOrganizationRepositoryLoadDomainsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// LoadMetadata mocks base method. +func (m *MockOrganizationRepository) LoadMetadata() domain.OrganizationRepository { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadMetadata") + ret0, _ := ret[0].(domain.OrganizationRepository) + return ret0 +} + +// LoadMetadata indicates an expected call of LoadMetadata. +func (mr *MockOrganizationRepositoryMockRecorder) LoadMetadata() *MockOrganizationRepositoryLoadMetadataCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadMetadata", reflect.TypeOf((*MockOrganizationRepository)(nil).LoadMetadata)) + return &MockOrganizationRepositoryLoadMetadataCall{Call: call} +} + +// MockOrganizationRepositoryLoadMetadataCall wrap *gomock.Call +type MockOrganizationRepositoryLoadMetadataCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryLoadMetadataCall) Return(arg0 domain.OrganizationRepository) *MockOrganizationRepositoryLoadMetadataCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryLoadMetadataCall) Do(f func() domain.OrganizationRepository) *MockOrganizationRepositoryLoadMetadataCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryLoadMetadataCall) DoAndReturn(f func() domain.OrganizationRepository) *MockOrganizationRepositoryLoadMetadataCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NameColumn mocks base method. +func (m *MockOrganizationRepository) NameColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NameColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// NameColumn indicates an expected call of NameColumn. +func (mr *MockOrganizationRepositoryMockRecorder) NameColumn() *MockOrganizationRepositoryNameColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NameColumn", reflect.TypeOf((*MockOrganizationRepository)(nil).NameColumn)) + return &MockOrganizationRepositoryNameColumnCall{Call: call} +} + +// MockOrganizationRepositoryNameColumnCall wrap *gomock.Call +type MockOrganizationRepositoryNameColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryNameColumnCall) Return(arg0 database.Column) *MockOrganizationRepositoryNameColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryNameColumnCall) Do(f func() database.Column) *MockOrganizationRepositoryNameColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryNameColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationRepositoryNameColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NameCondition mocks base method. +func (m *MockOrganizationRepository) NameCondition(op database.TextOperation, name string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NameCondition", op, name) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// NameCondition indicates an expected call of NameCondition. +func (mr *MockOrganizationRepositoryMockRecorder) NameCondition(op, name any) *MockOrganizationRepositoryNameConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NameCondition", reflect.TypeOf((*MockOrganizationRepository)(nil).NameCondition), op, name) + return &MockOrganizationRepositoryNameConditionCall{Call: call} +} + +// MockOrganizationRepositoryNameConditionCall wrap *gomock.Call +type MockOrganizationRepositoryNameConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryNameConditionCall) Return(arg0 database.Condition) *MockOrganizationRepositoryNameConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryNameConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockOrganizationRepositoryNameConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryNameConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockOrganizationRepositoryNameConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetName mocks base method. +func (m *MockOrganizationRepository) SetName(name string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetName", name) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetName indicates an expected call of SetName. +func (mr *MockOrganizationRepositoryMockRecorder) SetName(name any) *MockOrganizationRepositorySetNameCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetName", reflect.TypeOf((*MockOrganizationRepository)(nil).SetName), name) + return &MockOrganizationRepositorySetNameCall{Call: call} +} + +// MockOrganizationRepositorySetNameCall wrap *gomock.Call +type MockOrganizationRepositorySetNameCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositorySetNameCall) Return(arg0 database.Change) *MockOrganizationRepositorySetNameCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositorySetNameCall) Do(f func(string) database.Change) *MockOrganizationRepositorySetNameCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositorySetNameCall) DoAndReturn(f func(string) database.Change) *MockOrganizationRepositorySetNameCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetState mocks base method. +func (m *MockOrganizationRepository) SetState(state domain.OrgState) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetState", state) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetState indicates an expected call of SetState. +func (mr *MockOrganizationRepositoryMockRecorder) SetState(state any) *MockOrganizationRepositorySetStateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetState", reflect.TypeOf((*MockOrganizationRepository)(nil).SetState), state) + return &MockOrganizationRepositorySetStateCall{Call: call} +} + +// MockOrganizationRepositorySetStateCall wrap *gomock.Call +type MockOrganizationRepositorySetStateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositorySetStateCall) Return(arg0 database.Change) *MockOrganizationRepositorySetStateCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositorySetStateCall) Do(f func(domain.OrgState) database.Change) *MockOrganizationRepositorySetStateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositorySetStateCall) DoAndReturn(f func(domain.OrgState) database.Change) *MockOrganizationRepositorySetStateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// StateColumn mocks base method. +func (m *MockOrganizationRepository) StateColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// StateColumn indicates an expected call of StateColumn. +func (mr *MockOrganizationRepositoryMockRecorder) StateColumn() *MockOrganizationRepositoryStateColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateColumn", reflect.TypeOf((*MockOrganizationRepository)(nil).StateColumn)) + return &MockOrganizationRepositoryStateColumnCall{Call: call} +} + +// MockOrganizationRepositoryStateColumnCall wrap *gomock.Call +type MockOrganizationRepositoryStateColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryStateColumnCall) Return(arg0 database.Column) *MockOrganizationRepositoryStateColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryStateColumnCall) Do(f func() database.Column) *MockOrganizationRepositoryStateColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryStateColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationRepositoryStateColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// StateCondition mocks base method. +func (m *MockOrganizationRepository) StateCondition(state domain.OrgState) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateCondition", state) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// StateCondition indicates an expected call of StateCondition. +func (mr *MockOrganizationRepositoryMockRecorder) StateCondition(state any) *MockOrganizationRepositoryStateConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateCondition", reflect.TypeOf((*MockOrganizationRepository)(nil).StateCondition), state) + return &MockOrganizationRepositoryStateConditionCall{Call: call} +} + +// MockOrganizationRepositoryStateConditionCall wrap *gomock.Call +type MockOrganizationRepositoryStateConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryStateConditionCall) Return(arg0 database.Condition) *MockOrganizationRepositoryStateConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryStateConditionCall) Do(f func(domain.OrgState) database.Condition) *MockOrganizationRepositoryStateConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryStateConditionCall) DoAndReturn(f func(domain.OrgState) database.Condition) *MockOrganizationRepositoryStateConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Update mocks base method. +func (m *MockOrganizationRepository) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client, condition} + for _, a := range changes { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Update", varargs...) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockOrganizationRepositoryMockRecorder) Update(ctx, client, condition any, changes ...any) *MockOrganizationRepositoryUpdateCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client, condition}, changes...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockOrganizationRepository)(nil).Update), varargs...) + return &MockOrganizationRepositoryUpdateCall{Call: call} +} + +// MockOrganizationRepositoryUpdateCall wrap *gomock.Call +type MockOrganizationRepositoryUpdateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryUpdateCall) Return(arg0 int64, arg1 error) *MockOrganizationRepositoryUpdateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryUpdateCall) Do(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockOrganizationRepositoryUpdateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryUpdateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockOrganizationRepositoryUpdateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdatedAtColumn mocks base method. +func (m *MockOrganizationRepository) UpdatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// UpdatedAtColumn indicates an expected call of UpdatedAtColumn. +func (mr *MockOrganizationRepositoryMockRecorder) UpdatedAtColumn() *MockOrganizationRepositoryUpdatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtColumn", reflect.TypeOf((*MockOrganizationRepository)(nil).UpdatedAtColumn)) + return &MockOrganizationRepositoryUpdatedAtColumnCall{Call: call} +} + +// MockOrganizationRepositoryUpdatedAtColumnCall wrap *gomock.Call +type MockOrganizationRepositoryUpdatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationRepositoryUpdatedAtColumnCall) Return(arg0 database.Column) *MockOrganizationRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationRepositoryUpdatedAtColumnCall) Do(f func() database.Column) *MockOrganizationRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationRepositoryUpdatedAtColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationRepositoryUpdatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/backend/v3/domain/mock/org_domain.mock.go b/backend/v3/domain/mock/org_domain.mock.go new file mode 100644 index 000000000..68e73b038 --- /dev/null +++ b/backend/v3/domain/mock/org_domain.mock.go @@ -0,0 +1,899 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/zitadel/zitadel/backend/v3/domain (interfaces: OrganizationDomainRepository) +// +// Generated by this command: +// +// mockgen -typed -package domainmock -destination ./mock/org_domain.mock.go . OrganizationDomainRepository +// + +// Package domainmock is a generated GoMock package. +package domainmock + +import ( + context "context" + reflect "reflect" + time "time" + + domain "github.com/zitadel/zitadel/backend/v3/domain" + database "github.com/zitadel/zitadel/backend/v3/storage/database" + gomock "go.uber.org/mock/gomock" +) + +// MockOrganizationDomainRepository is a mock of OrganizationDomainRepository interface. +type MockOrganizationDomainRepository struct { + ctrl *gomock.Controller + recorder *MockOrganizationDomainRepositoryMockRecorder + isgomock struct{} +} + +// MockOrganizationDomainRepositoryMockRecorder is the mock recorder for MockOrganizationDomainRepository. +type MockOrganizationDomainRepositoryMockRecorder struct { + mock *MockOrganizationDomainRepository +} + +// NewMockOrganizationDomainRepository creates a new mock instance. +func NewMockOrganizationDomainRepository(ctrl *gomock.Controller) *MockOrganizationDomainRepository { + mock := &MockOrganizationDomainRepository{ctrl: ctrl} + mock.recorder = &MockOrganizationDomainRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockOrganizationDomainRepository) EXPECT() *MockOrganizationDomainRepositoryMockRecorder { + return m.recorder +} + +// Add mocks base method. +func (m *MockOrganizationDomainRepository) Add(ctx context.Context, client database.QueryExecutor, arg2 *domain.AddOrganizationDomain) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Add", ctx, client, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// Add indicates an expected call of Add. +func (mr *MockOrganizationDomainRepositoryMockRecorder) Add(ctx, client, arg2 any) *MockOrganizationDomainRepositoryAddCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).Add), ctx, client, arg2) + return &MockOrganizationDomainRepositoryAddCall{Call: call} +} + +// MockOrganizationDomainRepositoryAddCall wrap *gomock.Call +type MockOrganizationDomainRepositoryAddCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryAddCall) Return(arg0 error) *MockOrganizationDomainRepositoryAddCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryAddCall) Do(f func(context.Context, database.QueryExecutor, *domain.AddOrganizationDomain) error) *MockOrganizationDomainRepositoryAddCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryAddCall) DoAndReturn(f func(context.Context, database.QueryExecutor, *domain.AddOrganizationDomain) error) *MockOrganizationDomainRepositoryAddCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CreatedAtColumn mocks base method. +func (m *MockOrganizationDomainRepository) CreatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// CreatedAtColumn indicates an expected call of CreatedAtColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) CreatedAtColumn() *MockOrganizationDomainRepositoryCreatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).CreatedAtColumn)) + return &MockOrganizationDomainRepositoryCreatedAtColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryCreatedAtColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryCreatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryCreatedAtColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryCreatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryCreatedAtColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryCreatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryCreatedAtColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryCreatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// DomainColumn mocks base method. +func (m *MockOrganizationDomainRepository) DomainColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DomainColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// DomainColumn indicates an expected call of DomainColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) DomainColumn() *MockOrganizationDomainRepositoryDomainColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DomainColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).DomainColumn)) + return &MockOrganizationDomainRepositoryDomainColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryDomainColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryDomainColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryDomainColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryDomainColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryDomainColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryDomainColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryDomainColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryDomainColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// DomainCondition mocks base method. +func (m *MockOrganizationDomainRepository) DomainCondition(op database.TextOperation, arg1 string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DomainCondition", op, arg1) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// DomainCondition indicates an expected call of DomainCondition. +func (mr *MockOrganizationDomainRepositoryMockRecorder) DomainCondition(op, arg1 any) *MockOrganizationDomainRepositoryDomainConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DomainCondition", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).DomainCondition), op, arg1) + return &MockOrganizationDomainRepositoryDomainConditionCall{Call: call} +} + +// MockOrganizationDomainRepositoryDomainConditionCall wrap *gomock.Call +type MockOrganizationDomainRepositoryDomainConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryDomainConditionCall) Return(arg0 database.Condition) *MockOrganizationDomainRepositoryDomainConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryDomainConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockOrganizationDomainRepositoryDomainConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryDomainConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockOrganizationDomainRepositoryDomainConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Get mocks base method. +func (m *MockOrganizationDomainRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.OrganizationDomain, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Get", varargs...) + ret0, _ := ret[0].(*domain.OrganizationDomain) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockOrganizationDomainRepositoryMockRecorder) Get(ctx, client any, opts ...any) *MockOrganizationDomainRepositoryGetCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).Get), varargs...) + return &MockOrganizationDomainRepositoryGetCall{Call: call} +} + +// MockOrganizationDomainRepositoryGetCall wrap *gomock.Call +type MockOrganizationDomainRepositoryGetCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryGetCall) Return(arg0 *domain.OrganizationDomain, arg1 error) *MockOrganizationDomainRepositoryGetCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryGetCall) Do(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.OrganizationDomain, error)) *MockOrganizationDomainRepositoryGetCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryGetCall) DoAndReturn(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.OrganizationDomain, error)) *MockOrganizationDomainRepositoryGetCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDColumn mocks base method. +func (m *MockOrganizationDomainRepository) InstanceIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// InstanceIDColumn indicates an expected call of InstanceIDColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) InstanceIDColumn() *MockOrganizationDomainRepositoryInstanceIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).InstanceIDColumn)) + return &MockOrganizationDomainRepositoryInstanceIDColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryInstanceIDColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryInstanceIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryInstanceIDColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryInstanceIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryInstanceIDColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryInstanceIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryInstanceIDColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryInstanceIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDCondition mocks base method. +func (m *MockOrganizationDomainRepository) InstanceIDCondition(instanceID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDCondition", instanceID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// InstanceIDCondition indicates an expected call of InstanceIDCondition. +func (mr *MockOrganizationDomainRepositoryMockRecorder) InstanceIDCondition(instanceID any) *MockOrganizationDomainRepositoryInstanceIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDCondition", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).InstanceIDCondition), instanceID) + return &MockOrganizationDomainRepositoryInstanceIDConditionCall{Call: call} +} + +// MockOrganizationDomainRepositoryInstanceIDConditionCall wrap *gomock.Call +type MockOrganizationDomainRepositoryInstanceIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryInstanceIDConditionCall) Return(arg0 database.Condition) *MockOrganizationDomainRepositoryInstanceIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryInstanceIDConditionCall) Do(f func(string) database.Condition) *MockOrganizationDomainRepositoryInstanceIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryInstanceIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockOrganizationDomainRepositoryInstanceIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IsPrimaryColumn mocks base method. +func (m *MockOrganizationDomainRepository) IsPrimaryColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsPrimaryColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IsPrimaryColumn indicates an expected call of IsPrimaryColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) IsPrimaryColumn() *MockOrganizationDomainRepositoryIsPrimaryColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPrimaryColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).IsPrimaryColumn)) + return &MockOrganizationDomainRepositoryIsPrimaryColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryIsPrimaryColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryIsPrimaryColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryIsPrimaryColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryIsPrimaryColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryIsPrimaryColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryIsPrimaryColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryIsPrimaryColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryIsPrimaryColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IsPrimaryCondition mocks base method. +func (m *MockOrganizationDomainRepository) IsPrimaryCondition(isPrimary bool) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsPrimaryCondition", isPrimary) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IsPrimaryCondition indicates an expected call of IsPrimaryCondition. +func (mr *MockOrganizationDomainRepositoryMockRecorder) IsPrimaryCondition(isPrimary any) *MockOrganizationDomainRepositoryIsPrimaryConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsPrimaryCondition", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).IsPrimaryCondition), isPrimary) + return &MockOrganizationDomainRepositoryIsPrimaryConditionCall{Call: call} +} + +// MockOrganizationDomainRepositoryIsPrimaryConditionCall wrap *gomock.Call +type MockOrganizationDomainRepositoryIsPrimaryConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryIsPrimaryConditionCall) Return(arg0 database.Condition) *MockOrganizationDomainRepositoryIsPrimaryConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryIsPrimaryConditionCall) Do(f func(bool) database.Condition) *MockOrganizationDomainRepositoryIsPrimaryConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryIsPrimaryConditionCall) DoAndReturn(f func(bool) database.Condition) *MockOrganizationDomainRepositoryIsPrimaryConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IsVerifiedColumn mocks base method. +func (m *MockOrganizationDomainRepository) IsVerifiedColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsVerifiedColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IsVerifiedColumn indicates an expected call of IsVerifiedColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) IsVerifiedColumn() *MockOrganizationDomainRepositoryIsVerifiedColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsVerifiedColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).IsVerifiedColumn)) + return &MockOrganizationDomainRepositoryIsVerifiedColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryIsVerifiedColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryIsVerifiedColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryIsVerifiedColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryIsVerifiedColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryIsVerifiedColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryIsVerifiedColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryIsVerifiedColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryIsVerifiedColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IsVerifiedCondition mocks base method. +func (m *MockOrganizationDomainRepository) IsVerifiedCondition(isVerified bool) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsVerifiedCondition", isVerified) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IsVerifiedCondition indicates an expected call of IsVerifiedCondition. +func (mr *MockOrganizationDomainRepositoryMockRecorder) IsVerifiedCondition(isVerified any) *MockOrganizationDomainRepositoryIsVerifiedConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsVerifiedCondition", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).IsVerifiedCondition), isVerified) + return &MockOrganizationDomainRepositoryIsVerifiedConditionCall{Call: call} +} + +// MockOrganizationDomainRepositoryIsVerifiedConditionCall wrap *gomock.Call +type MockOrganizationDomainRepositoryIsVerifiedConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryIsVerifiedConditionCall) Return(arg0 database.Condition) *MockOrganizationDomainRepositoryIsVerifiedConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryIsVerifiedConditionCall) Do(f func(bool) database.Condition) *MockOrganizationDomainRepositoryIsVerifiedConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryIsVerifiedConditionCall) DoAndReturn(f func(bool) database.Condition) *MockOrganizationDomainRepositoryIsVerifiedConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// List mocks base method. +func (m *MockOrganizationDomainRepository) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.OrganizationDomain, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "List", varargs...) + ret0, _ := ret[0].([]*domain.OrganizationDomain) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockOrganizationDomainRepositoryMockRecorder) List(ctx, client any, opts ...any) *MockOrganizationDomainRepositoryListCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).List), varargs...) + return &MockOrganizationDomainRepositoryListCall{Call: call} +} + +// MockOrganizationDomainRepositoryListCall wrap *gomock.Call +type MockOrganizationDomainRepositoryListCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryListCall) Return(arg0 []*domain.OrganizationDomain, arg1 error) *MockOrganizationDomainRepositoryListCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryListCall) Do(f func(context.Context, database.QueryExecutor, ...database.QueryOption) ([]*domain.OrganizationDomain, error)) *MockOrganizationDomainRepositoryListCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryListCall) DoAndReturn(f func(context.Context, database.QueryExecutor, ...database.QueryOption) ([]*domain.OrganizationDomain, error)) *MockOrganizationDomainRepositoryListCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// OrgIDColumn mocks base method. +func (m *MockOrganizationDomainRepository) OrgIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OrgIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// OrgIDColumn indicates an expected call of OrgIDColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) OrgIDColumn() *MockOrganizationDomainRepositoryOrgIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrgIDColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).OrgIDColumn)) + return &MockOrganizationDomainRepositoryOrgIDColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryOrgIDColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryOrgIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryOrgIDColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryOrgIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryOrgIDColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryOrgIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryOrgIDColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryOrgIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// OrgIDCondition mocks base method. +func (m *MockOrganizationDomainRepository) OrgIDCondition(orgID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OrgIDCondition", orgID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// OrgIDCondition indicates an expected call of OrgIDCondition. +func (mr *MockOrganizationDomainRepositoryMockRecorder) OrgIDCondition(orgID any) *MockOrganizationDomainRepositoryOrgIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrgIDCondition", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).OrgIDCondition), orgID) + return &MockOrganizationDomainRepositoryOrgIDConditionCall{Call: call} +} + +// MockOrganizationDomainRepositoryOrgIDConditionCall wrap *gomock.Call +type MockOrganizationDomainRepositoryOrgIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryOrgIDConditionCall) Return(arg0 database.Condition) *MockOrganizationDomainRepositoryOrgIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryOrgIDConditionCall) Do(f func(string) database.Condition) *MockOrganizationDomainRepositoryOrgIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryOrgIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockOrganizationDomainRepositoryOrgIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Remove mocks base method. +func (m *MockOrganizationDomainRepository) Remove(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Remove", ctx, client, condition) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Remove indicates an expected call of Remove. +func (mr *MockOrganizationDomainRepositoryMockRecorder) Remove(ctx, client, condition any) *MockOrganizationDomainRepositoryRemoveCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remove", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).Remove), ctx, client, condition) + return &MockOrganizationDomainRepositoryRemoveCall{Call: call} +} + +// MockOrganizationDomainRepositoryRemoveCall wrap *gomock.Call +type MockOrganizationDomainRepositoryRemoveCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryRemoveCall) Return(arg0 int64, arg1 error) *MockOrganizationDomainRepositoryRemoveCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryRemoveCall) Do(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockOrganizationDomainRepositoryRemoveCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryRemoveCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockOrganizationDomainRepositoryRemoveCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetPrimary mocks base method. +func (m *MockOrganizationDomainRepository) SetPrimary() database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetPrimary") + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetPrimary indicates an expected call of SetPrimary. +func (mr *MockOrganizationDomainRepositoryMockRecorder) SetPrimary() *MockOrganizationDomainRepositorySetPrimaryCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetPrimary", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).SetPrimary)) + return &MockOrganizationDomainRepositorySetPrimaryCall{Call: call} +} + +// MockOrganizationDomainRepositorySetPrimaryCall wrap *gomock.Call +type MockOrganizationDomainRepositorySetPrimaryCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositorySetPrimaryCall) Return(arg0 database.Change) *MockOrganizationDomainRepositorySetPrimaryCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositorySetPrimaryCall) Do(f func() database.Change) *MockOrganizationDomainRepositorySetPrimaryCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositorySetPrimaryCall) DoAndReturn(f func() database.Change) *MockOrganizationDomainRepositorySetPrimaryCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetUpdatedAt mocks base method. +func (m *MockOrganizationDomainRepository) SetUpdatedAt(t time.Time) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUpdatedAt", t) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetUpdatedAt indicates an expected call of SetUpdatedAt. +func (mr *MockOrganizationDomainRepositoryMockRecorder) SetUpdatedAt(t any) *MockOrganizationDomainRepositorySetUpdatedAtCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUpdatedAt", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).SetUpdatedAt), t) + return &MockOrganizationDomainRepositorySetUpdatedAtCall{Call: call} +} + +// MockOrganizationDomainRepositorySetUpdatedAtCall wrap *gomock.Call +type MockOrganizationDomainRepositorySetUpdatedAtCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositorySetUpdatedAtCall) Return(arg0 database.Change) *MockOrganizationDomainRepositorySetUpdatedAtCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositorySetUpdatedAtCall) Do(f func(time.Time) database.Change) *MockOrganizationDomainRepositorySetUpdatedAtCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositorySetUpdatedAtCall) DoAndReturn(f func(time.Time) database.Change) *MockOrganizationDomainRepositorySetUpdatedAtCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetValidationType mocks base method. +func (m *MockOrganizationDomainRepository) SetValidationType(verificationType domain.DomainValidationType) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetValidationType", verificationType) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetValidationType indicates an expected call of SetValidationType. +func (mr *MockOrganizationDomainRepositoryMockRecorder) SetValidationType(verificationType any) *MockOrganizationDomainRepositorySetValidationTypeCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetValidationType", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).SetValidationType), verificationType) + return &MockOrganizationDomainRepositorySetValidationTypeCall{Call: call} +} + +// MockOrganizationDomainRepositorySetValidationTypeCall wrap *gomock.Call +type MockOrganizationDomainRepositorySetValidationTypeCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositorySetValidationTypeCall) Return(arg0 database.Change) *MockOrganizationDomainRepositorySetValidationTypeCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositorySetValidationTypeCall) Do(f func(domain.DomainValidationType) database.Change) *MockOrganizationDomainRepositorySetValidationTypeCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositorySetValidationTypeCall) DoAndReturn(f func(domain.DomainValidationType) database.Change) *MockOrganizationDomainRepositorySetValidationTypeCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetVerified mocks base method. +func (m *MockOrganizationDomainRepository) SetVerified() database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetVerified") + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetVerified indicates an expected call of SetVerified. +func (mr *MockOrganizationDomainRepositoryMockRecorder) SetVerified() *MockOrganizationDomainRepositorySetVerifiedCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetVerified", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).SetVerified)) + return &MockOrganizationDomainRepositorySetVerifiedCall{Call: call} +} + +// MockOrganizationDomainRepositorySetVerifiedCall wrap *gomock.Call +type MockOrganizationDomainRepositorySetVerifiedCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositorySetVerifiedCall) Return(arg0 database.Change) *MockOrganizationDomainRepositorySetVerifiedCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositorySetVerifiedCall) Do(f func() database.Change) *MockOrganizationDomainRepositorySetVerifiedCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositorySetVerifiedCall) DoAndReturn(f func() database.Change) *MockOrganizationDomainRepositorySetVerifiedCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Update mocks base method. +func (m *MockOrganizationDomainRepository) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client, condition} + for _, a := range changes { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Update", varargs...) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockOrganizationDomainRepositoryMockRecorder) Update(ctx, client, condition any, changes ...any) *MockOrganizationDomainRepositoryUpdateCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client, condition}, changes...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).Update), varargs...) + return &MockOrganizationDomainRepositoryUpdateCall{Call: call} +} + +// MockOrganizationDomainRepositoryUpdateCall wrap *gomock.Call +type MockOrganizationDomainRepositoryUpdateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryUpdateCall) Return(arg0 int64, arg1 error) *MockOrganizationDomainRepositoryUpdateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryUpdateCall) Do(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockOrganizationDomainRepositoryUpdateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryUpdateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockOrganizationDomainRepositoryUpdateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdatedAtColumn mocks base method. +func (m *MockOrganizationDomainRepository) UpdatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// UpdatedAtColumn indicates an expected call of UpdatedAtColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) UpdatedAtColumn() *MockOrganizationDomainRepositoryUpdatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).UpdatedAtColumn)) + return &MockOrganizationDomainRepositoryUpdatedAtColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryUpdatedAtColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryUpdatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryUpdatedAtColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryUpdatedAtColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryUpdatedAtColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryUpdatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ValidationTypeColumn mocks base method. +func (m *MockOrganizationDomainRepository) ValidationTypeColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ValidationTypeColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// ValidationTypeColumn indicates an expected call of ValidationTypeColumn. +func (mr *MockOrganizationDomainRepositoryMockRecorder) ValidationTypeColumn() *MockOrganizationDomainRepositoryValidationTypeColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidationTypeColumn", reflect.TypeOf((*MockOrganizationDomainRepository)(nil).ValidationTypeColumn)) + return &MockOrganizationDomainRepositoryValidationTypeColumnCall{Call: call} +} + +// MockOrganizationDomainRepositoryValidationTypeColumnCall wrap *gomock.Call +type MockOrganizationDomainRepositoryValidationTypeColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockOrganizationDomainRepositoryValidationTypeColumnCall) Return(arg0 database.Column) *MockOrganizationDomainRepositoryValidationTypeColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockOrganizationDomainRepositoryValidationTypeColumnCall) Do(f func() database.Column) *MockOrganizationDomainRepositoryValidationTypeColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockOrganizationDomainRepositoryValidationTypeColumnCall) DoAndReturn(f func() database.Column) *MockOrganizationDomainRepositoryValidationTypeColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/backend/v3/domain/mock/org_domain_repo.go b/backend/v3/domain/mock/org_domain_repo.go new file mode 100644 index 000000000..0b29f4d98 --- /dev/null +++ b/backend/v3/domain/mock/org_domain_repo.go @@ -0,0 +1,48 @@ +package domainmock + +import ( + context "context" + + gomock "go.uber.org/mock/gomock" + + domain "github.com/zitadel/zitadel/backend/v3/domain" + database "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/repository" +) + +type OrgDomainRepo struct { + domain.OrganizationDomainRepository + mock *MockOrganizationDomainRepository +} + +func NewOrgDomainRepo(ctrl *gomock.Controller) *OrgDomainRepo { + return &OrgDomainRepo{ + mock: NewMockOrganizationDomainRepository(ctrl), + OrganizationDomainRepository: repository.OrganizationDomainRepository(), + } +} + +func (r *OrgDomainRepo) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.OrganizationDomain, error) { + return r.mock.Get(ctx, client, opts...) + +} + +func (r *OrgDomainRepo) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.OrganizationDomain, error) { + return r.mock.List(ctx, client, opts...) + +} + +func (r *OrgDomainRepo) Add(ctx context.Context, client database.QueryExecutor, domain *domain.AddOrganizationDomain) error { + return r.mock.Add(ctx, client, domain) + +} + +func (r *OrgDomainRepo) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) { + return r.mock.Update(ctx, client, condition, changes...) + +} + +func (r *OrgDomainRepo) Remove(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) { + return r.mock.Remove(ctx, client, condition) + +} diff --git a/backend/v3/domain/mock/org_repo.go b/backend/v3/domain/mock/org_repo.go new file mode 100644 index 000000000..b55dd7dd9 --- /dev/null +++ b/backend/v3/domain/mock/org_repo.go @@ -0,0 +1,69 @@ +package domainmock + +import ( + context "context" + + gomock "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + database "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/repository" +) + +func NewOrgRepo(ctrl *gomock.Controller) *OrgRepo { + return &OrgRepo{ + mock: NewMockOrganizationRepository(ctrl), + OrganizationRepository: repository.OrganizationRepository(), + } +} + +type OrgRepo struct { + domain.OrganizationRepository + mock *MockOrganizationRepository + domainRepo *OrgDomainRepo + + existDomain database.Condition +} + +func (r *OrgRepo) SetDomains(repo *OrgDomainRepo) { + r.domainRepo = repo +} + +// SetExistsDomain is a helper function that allows to skip calling EXISTS() when ExistsDomain() is called. +// You will not be able to mock the ExistsDomain() call though +func (r *OrgRepo) SetExistsDomain(existsDomainCondition database.Condition) { + r.existDomain = existsDomainCondition + +} + +func (r *OrgRepo) ExistsDomain(_ database.Condition) database.Condition { + return r.existDomain +} + +func (r *OrgRepo) EXPECT() *MockOrganizationRepositoryMockRecorder { + return r.mock.EXPECT() +} + +func (r *OrgRepo) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Organization, error) { + return r.mock.Get(ctx, client, opts...) +} + +func (r *OrgRepo) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.Organization, error) { + return r.mock.List(ctx, client, opts...) +} + +func (r *OrgRepo) Create(ctx context.Context, client database.QueryExecutor, org *domain.Organization) error { + return r.mock.Create(ctx, client, org) +} + +func (r *OrgRepo) Update(ctx context.Context, client database.QueryExecutor, conditions database.Condition, changes ...database.Change) (int64, error) { + return r.mock.Update(ctx, client, conditions, changes...) +} + +func (r *OrgRepo) Delete(ctx context.Context, client database.QueryExecutor, conditions database.Condition) (int64, error) { + return r.mock.Delete(ctx, client, conditions) +} + +func (r *OrgRepo) LoadDomains() domain.OrganizationRepository { + return r.mock.LoadDomains() +} diff --git a/backend/v3/domain/mock/project.mock.go b/backend/v3/domain/mock/project.mock.go new file mode 100644 index 000000000..9fcb2d4db --- /dev/null +++ b/backend/v3/domain/mock/project.mock.go @@ -0,0 +1,1241 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/zitadel/zitadel/backend/v3/domain (interfaces: ProjectRepository) +// +// Generated by this command: +// +// mockgen -typed -package domainmock -destination ./mock/project.mock.go . ProjectRepository +// + +// Package domainmock is a generated GoMock package. +package domainmock + +import ( + context "context" + reflect "reflect" + time "time" + + domain "github.com/zitadel/zitadel/backend/v3/domain" + database "github.com/zitadel/zitadel/backend/v3/storage/database" + gomock "go.uber.org/mock/gomock" +) + +// MockProjectRepository is a mock of ProjectRepository interface. +type MockProjectRepository struct { + ctrl *gomock.Controller + recorder *MockProjectRepositoryMockRecorder + isgomock struct{} +} + +// MockProjectRepositoryMockRecorder is the mock recorder for MockProjectRepository. +type MockProjectRepositoryMockRecorder struct { + mock *MockProjectRepository +} + +// NewMockProjectRepository creates a new mock instance. +func NewMockProjectRepository(ctrl *gomock.Controller) *MockProjectRepository { + mock := &MockProjectRepository{ctrl: ctrl} + mock.recorder = &MockProjectRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockProjectRepository) EXPECT() *MockProjectRepositoryMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockProjectRepository) Create(ctx context.Context, client database.QueryExecutor, project *domain.Project) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, client, project) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockProjectRepositoryMockRecorder) Create(ctx, client, project any) *MockProjectRepositoryCreateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockProjectRepository)(nil).Create), ctx, client, project) + return &MockProjectRepositoryCreateCall{Call: call} +} + +// MockProjectRepositoryCreateCall wrap *gomock.Call +type MockProjectRepositoryCreateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryCreateCall) Return(arg0 error) *MockProjectRepositoryCreateCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryCreateCall) Do(f func(context.Context, database.QueryExecutor, *domain.Project) error) *MockProjectRepositoryCreateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryCreateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, *domain.Project) error) *MockProjectRepositoryCreateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CreatedAtColumn mocks base method. +func (m *MockProjectRepository) CreatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// CreatedAtColumn indicates an expected call of CreatedAtColumn. +func (mr *MockProjectRepositoryMockRecorder) CreatedAtColumn() *MockProjectRepositoryCreatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtColumn", reflect.TypeOf((*MockProjectRepository)(nil).CreatedAtColumn)) + return &MockProjectRepositoryCreatedAtColumnCall{Call: call} +} + +// MockProjectRepositoryCreatedAtColumnCall wrap *gomock.Call +type MockProjectRepositoryCreatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryCreatedAtColumnCall) Return(arg0 database.Column) *MockProjectRepositoryCreatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryCreatedAtColumnCall) Do(f func() database.Column) *MockProjectRepositoryCreatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryCreatedAtColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryCreatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Delete mocks base method. +func (m *MockProjectRepository) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, client, condition) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockProjectRepositoryMockRecorder) Delete(ctx, client, condition any) *MockProjectRepositoryDeleteCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockProjectRepository)(nil).Delete), ctx, client, condition) + return &MockProjectRepositoryDeleteCall{Call: call} +} + +// MockProjectRepositoryDeleteCall wrap *gomock.Call +type MockProjectRepositoryDeleteCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryDeleteCall) Return(arg0 int64, arg1 error) *MockProjectRepositoryDeleteCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryDeleteCall) Do(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockProjectRepositoryDeleteCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryDeleteCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockProjectRepositoryDeleteCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Get mocks base method. +func (m *MockProjectRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Project, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Get", varargs...) + ret0, _ := ret[0].(*domain.Project) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockProjectRepositoryMockRecorder) Get(ctx, client any, opts ...any) *MockProjectRepositoryGetCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockProjectRepository)(nil).Get), varargs...) + return &MockProjectRepositoryGetCall{Call: call} +} + +// MockProjectRepositoryGetCall wrap *gomock.Call +type MockProjectRepositoryGetCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryGetCall) Return(arg0 *domain.Project, arg1 error) *MockProjectRepositoryGetCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryGetCall) Do(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.Project, error)) *MockProjectRepositoryGetCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryGetCall) DoAndReturn(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.Project, error)) *MockProjectRepositoryGetCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDColumn mocks base method. +func (m *MockProjectRepository) IDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDColumn indicates an expected call of IDColumn. +func (mr *MockProjectRepositoryMockRecorder) IDColumn() *MockProjectRepositoryIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDColumn", reflect.TypeOf((*MockProjectRepository)(nil).IDColumn)) + return &MockProjectRepositoryIDColumnCall{Call: call} +} + +// MockProjectRepositoryIDColumnCall wrap *gomock.Call +type MockProjectRepositoryIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryIDColumnCall) Return(arg0 database.Column) *MockProjectRepositoryIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryIDColumnCall) Do(f func() database.Column) *MockProjectRepositoryIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryIDColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDCondition mocks base method. +func (m *MockProjectRepository) IDCondition(projectID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDCondition", projectID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IDCondition indicates an expected call of IDCondition. +func (mr *MockProjectRepositoryMockRecorder) IDCondition(projectID any) *MockProjectRepositoryIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDCondition", reflect.TypeOf((*MockProjectRepository)(nil).IDCondition), projectID) + return &MockProjectRepositoryIDConditionCall{Call: call} +} + +// MockProjectRepositoryIDConditionCall wrap *gomock.Call +type MockProjectRepositoryIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryIDConditionCall) Return(arg0 database.Condition) *MockProjectRepositoryIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryIDConditionCall) Do(f func(string) database.Condition) *MockProjectRepositoryIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockProjectRepositoryIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDColumn mocks base method. +func (m *MockProjectRepository) InstanceIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// InstanceIDColumn indicates an expected call of InstanceIDColumn. +func (mr *MockProjectRepositoryMockRecorder) InstanceIDColumn() *MockProjectRepositoryInstanceIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDColumn", reflect.TypeOf((*MockProjectRepository)(nil).InstanceIDColumn)) + return &MockProjectRepositoryInstanceIDColumnCall{Call: call} +} + +// MockProjectRepositoryInstanceIDColumnCall wrap *gomock.Call +type MockProjectRepositoryInstanceIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryInstanceIDColumnCall) Return(arg0 database.Column) *MockProjectRepositoryInstanceIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryInstanceIDColumnCall) Do(f func() database.Column) *MockProjectRepositoryInstanceIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryInstanceIDColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryInstanceIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDCondition mocks base method. +func (m *MockProjectRepository) InstanceIDCondition(instanceID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDCondition", instanceID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// InstanceIDCondition indicates an expected call of InstanceIDCondition. +func (mr *MockProjectRepositoryMockRecorder) InstanceIDCondition(instanceID any) *MockProjectRepositoryInstanceIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDCondition", reflect.TypeOf((*MockProjectRepository)(nil).InstanceIDCondition), instanceID) + return &MockProjectRepositoryInstanceIDConditionCall{Call: call} +} + +// MockProjectRepositoryInstanceIDConditionCall wrap *gomock.Call +type MockProjectRepositoryInstanceIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryInstanceIDConditionCall) Return(arg0 database.Condition) *MockProjectRepositoryInstanceIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryInstanceIDConditionCall) Do(f func(string) database.Condition) *MockProjectRepositoryInstanceIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryInstanceIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockProjectRepositoryInstanceIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IsAuthorizationRequiredColumn mocks base method. +func (m *MockProjectRepository) IsAuthorizationRequiredColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsAuthorizationRequiredColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IsAuthorizationRequiredColumn indicates an expected call of IsAuthorizationRequiredColumn. +func (mr *MockProjectRepositoryMockRecorder) IsAuthorizationRequiredColumn() *MockProjectRepositoryIsAuthorizationRequiredColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAuthorizationRequiredColumn", reflect.TypeOf((*MockProjectRepository)(nil).IsAuthorizationRequiredColumn)) + return &MockProjectRepositoryIsAuthorizationRequiredColumnCall{Call: call} +} + +// MockProjectRepositoryIsAuthorizationRequiredColumnCall wrap *gomock.Call +type MockProjectRepositoryIsAuthorizationRequiredColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryIsAuthorizationRequiredColumnCall) Return(arg0 database.Column) *MockProjectRepositoryIsAuthorizationRequiredColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryIsAuthorizationRequiredColumnCall) Do(f func() database.Column) *MockProjectRepositoryIsAuthorizationRequiredColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryIsAuthorizationRequiredColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryIsAuthorizationRequiredColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IsProjectAccessRequiredColumn mocks base method. +func (m *MockProjectRepository) IsProjectAccessRequiredColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsProjectAccessRequiredColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IsProjectAccessRequiredColumn indicates an expected call of IsProjectAccessRequiredColumn. +func (mr *MockProjectRepositoryMockRecorder) IsProjectAccessRequiredColumn() *MockProjectRepositoryIsProjectAccessRequiredColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsProjectAccessRequiredColumn", reflect.TypeOf((*MockProjectRepository)(nil).IsProjectAccessRequiredColumn)) + return &MockProjectRepositoryIsProjectAccessRequiredColumnCall{Call: call} +} + +// MockProjectRepositoryIsProjectAccessRequiredColumnCall wrap *gomock.Call +type MockProjectRepositoryIsProjectAccessRequiredColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryIsProjectAccessRequiredColumnCall) Return(arg0 database.Column) *MockProjectRepositoryIsProjectAccessRequiredColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryIsProjectAccessRequiredColumnCall) Do(f func() database.Column) *MockProjectRepositoryIsProjectAccessRequiredColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryIsProjectAccessRequiredColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryIsProjectAccessRequiredColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// List mocks base method. +func (m *MockProjectRepository) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.Project, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "List", varargs...) + ret0, _ := ret[0].([]*domain.Project) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// List indicates an expected call of List. +func (mr *MockProjectRepositoryMockRecorder) List(ctx, client any, opts ...any) *MockProjectRepositoryListCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockProjectRepository)(nil).List), varargs...) + return &MockProjectRepositoryListCall{Call: call} +} + +// MockProjectRepositoryListCall wrap *gomock.Call +type MockProjectRepositoryListCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryListCall) Return(arg0 []*domain.Project, arg1 error) *MockProjectRepositoryListCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryListCall) Do(f func(context.Context, database.QueryExecutor, ...database.QueryOption) ([]*domain.Project, error)) *MockProjectRepositoryListCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryListCall) DoAndReturn(f func(context.Context, database.QueryExecutor, ...database.QueryOption) ([]*domain.Project, error)) *MockProjectRepositoryListCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NameColumn mocks base method. +func (m *MockProjectRepository) NameColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NameColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// NameColumn indicates an expected call of NameColumn. +func (mr *MockProjectRepositoryMockRecorder) NameColumn() *MockProjectRepositoryNameColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NameColumn", reflect.TypeOf((*MockProjectRepository)(nil).NameColumn)) + return &MockProjectRepositoryNameColumnCall{Call: call} +} + +// MockProjectRepositoryNameColumnCall wrap *gomock.Call +type MockProjectRepositoryNameColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryNameColumnCall) Return(arg0 database.Column) *MockProjectRepositoryNameColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryNameColumnCall) Do(f func() database.Column) *MockProjectRepositoryNameColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryNameColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryNameColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// NameCondition mocks base method. +func (m *MockProjectRepository) NameCondition(op database.TextOperation, name string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NameCondition", op, name) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// NameCondition indicates an expected call of NameCondition. +func (mr *MockProjectRepositoryMockRecorder) NameCondition(op, name any) *MockProjectRepositoryNameConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NameCondition", reflect.TypeOf((*MockProjectRepository)(nil).NameCondition), op, name) + return &MockProjectRepositoryNameConditionCall{Call: call} +} + +// MockProjectRepositoryNameConditionCall wrap *gomock.Call +type MockProjectRepositoryNameConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryNameConditionCall) Return(arg0 database.Condition) *MockProjectRepositoryNameConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryNameConditionCall) Do(f func(database.TextOperation, string) database.Condition) *MockProjectRepositoryNameConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryNameConditionCall) DoAndReturn(f func(database.TextOperation, string) database.Condition) *MockProjectRepositoryNameConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// OrganizationIDColumn mocks base method. +func (m *MockProjectRepository) OrganizationIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OrganizationIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// OrganizationIDColumn indicates an expected call of OrganizationIDColumn. +func (mr *MockProjectRepositoryMockRecorder) OrganizationIDColumn() *MockProjectRepositoryOrganizationIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrganizationIDColumn", reflect.TypeOf((*MockProjectRepository)(nil).OrganizationIDColumn)) + return &MockProjectRepositoryOrganizationIDColumnCall{Call: call} +} + +// MockProjectRepositoryOrganizationIDColumnCall wrap *gomock.Call +type MockProjectRepositoryOrganizationIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryOrganizationIDColumnCall) Return(arg0 database.Column) *MockProjectRepositoryOrganizationIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryOrganizationIDColumnCall) Do(f func() database.Column) *MockProjectRepositoryOrganizationIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryOrganizationIDColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryOrganizationIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// OrganizationIDCondition mocks base method. +func (m *MockProjectRepository) OrganizationIDCondition(organizationID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OrganizationIDCondition", organizationID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// OrganizationIDCondition indicates an expected call of OrganizationIDCondition. +func (mr *MockProjectRepositoryMockRecorder) OrganizationIDCondition(organizationID any) *MockProjectRepositoryOrganizationIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrganizationIDCondition", reflect.TypeOf((*MockProjectRepository)(nil).OrganizationIDCondition), organizationID) + return &MockProjectRepositoryOrganizationIDConditionCall{Call: call} +} + +// MockProjectRepositoryOrganizationIDConditionCall wrap *gomock.Call +type MockProjectRepositoryOrganizationIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryOrganizationIDConditionCall) Return(arg0 database.Condition) *MockProjectRepositoryOrganizationIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryOrganizationIDConditionCall) Do(f func(string) database.Condition) *MockProjectRepositoryOrganizationIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryOrganizationIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockProjectRepositoryOrganizationIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PrimaryKeyColumns mocks base method. +func (m *MockProjectRepository) PrimaryKeyColumns() []database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrimaryKeyColumns") + ret0, _ := ret[0].([]database.Column) + return ret0 +} + +// PrimaryKeyColumns indicates an expected call of PrimaryKeyColumns. +func (mr *MockProjectRepositoryMockRecorder) PrimaryKeyColumns() *MockProjectRepositoryPrimaryKeyColumnsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyColumns", reflect.TypeOf((*MockProjectRepository)(nil).PrimaryKeyColumns)) + return &MockProjectRepositoryPrimaryKeyColumnsCall{Call: call} +} + +// MockProjectRepositoryPrimaryKeyColumnsCall wrap *gomock.Call +type MockProjectRepositoryPrimaryKeyColumnsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryPrimaryKeyColumnsCall) Return(arg0 []database.Column) *MockProjectRepositoryPrimaryKeyColumnsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryPrimaryKeyColumnsCall) Do(f func() []database.Column) *MockProjectRepositoryPrimaryKeyColumnsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryPrimaryKeyColumnsCall) DoAndReturn(f func() []database.Column) *MockProjectRepositoryPrimaryKeyColumnsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PrimaryKeyCondition mocks base method. +func (m *MockProjectRepository) PrimaryKeyCondition(instanceID, projectID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrimaryKeyCondition", instanceID, projectID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// PrimaryKeyCondition indicates an expected call of PrimaryKeyCondition. +func (mr *MockProjectRepositoryMockRecorder) PrimaryKeyCondition(instanceID, projectID any) *MockProjectRepositoryPrimaryKeyConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyCondition", reflect.TypeOf((*MockProjectRepository)(nil).PrimaryKeyCondition), instanceID, projectID) + return &MockProjectRepositoryPrimaryKeyConditionCall{Call: call} +} + +// MockProjectRepositoryPrimaryKeyConditionCall wrap *gomock.Call +type MockProjectRepositoryPrimaryKeyConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryPrimaryKeyConditionCall) Return(arg0 database.Condition) *MockProjectRepositoryPrimaryKeyConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryPrimaryKeyConditionCall) Do(f func(string, string) database.Condition) *MockProjectRepositoryPrimaryKeyConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryPrimaryKeyConditionCall) DoAndReturn(f func(string, string) database.Condition) *MockProjectRepositoryPrimaryKeyConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Role mocks base method. +func (m *MockProjectRepository) Role() domain.ProjectRoleRepository { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Role") + ret0, _ := ret[0].(domain.ProjectRoleRepository) + return ret0 +} + +// Role indicates an expected call of Role. +func (mr *MockProjectRepositoryMockRecorder) Role() *MockProjectRepositoryRoleCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Role", reflect.TypeOf((*MockProjectRepository)(nil).Role)) + return &MockProjectRepositoryRoleCall{Call: call} +} + +// MockProjectRepositoryRoleCall wrap *gomock.Call +type MockProjectRepositoryRoleCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryRoleCall) Return(arg0 domain.ProjectRoleRepository) *MockProjectRepositoryRoleCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryRoleCall) Do(f func() domain.ProjectRoleRepository) *MockProjectRepositoryRoleCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryRoleCall) DoAndReturn(f func() domain.ProjectRoleRepository) *MockProjectRepositoryRoleCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIsAuthorizationRequired mocks base method. +func (m *MockProjectRepository) SetIsAuthorizationRequired(isAuthorizationRequired bool) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIsAuthorizationRequired", isAuthorizationRequired) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIsAuthorizationRequired indicates an expected call of SetIsAuthorizationRequired. +func (mr *MockProjectRepositoryMockRecorder) SetIsAuthorizationRequired(isAuthorizationRequired any) *MockProjectRepositorySetIsAuthorizationRequiredCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIsAuthorizationRequired", reflect.TypeOf((*MockProjectRepository)(nil).SetIsAuthorizationRequired), isAuthorizationRequired) + return &MockProjectRepositorySetIsAuthorizationRequiredCall{Call: call} +} + +// MockProjectRepositorySetIsAuthorizationRequiredCall wrap *gomock.Call +type MockProjectRepositorySetIsAuthorizationRequiredCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositorySetIsAuthorizationRequiredCall) Return(arg0 database.Change) *MockProjectRepositorySetIsAuthorizationRequiredCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositorySetIsAuthorizationRequiredCall) Do(f func(bool) database.Change) *MockProjectRepositorySetIsAuthorizationRequiredCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositorySetIsAuthorizationRequiredCall) DoAndReturn(f func(bool) database.Change) *MockProjectRepositorySetIsAuthorizationRequiredCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIsProjectAccessRequired mocks base method. +func (m *MockProjectRepository) SetIsProjectAccessRequired(isProjectAccessRequired bool) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIsProjectAccessRequired", isProjectAccessRequired) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIsProjectAccessRequired indicates an expected call of SetIsProjectAccessRequired. +func (mr *MockProjectRepositoryMockRecorder) SetIsProjectAccessRequired(isProjectAccessRequired any) *MockProjectRepositorySetIsProjectAccessRequiredCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIsProjectAccessRequired", reflect.TypeOf((*MockProjectRepository)(nil).SetIsProjectAccessRequired), isProjectAccessRequired) + return &MockProjectRepositorySetIsProjectAccessRequiredCall{Call: call} +} + +// MockProjectRepositorySetIsProjectAccessRequiredCall wrap *gomock.Call +type MockProjectRepositorySetIsProjectAccessRequiredCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositorySetIsProjectAccessRequiredCall) Return(arg0 database.Change) *MockProjectRepositorySetIsProjectAccessRequiredCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositorySetIsProjectAccessRequiredCall) Do(f func(bool) database.Change) *MockProjectRepositorySetIsProjectAccessRequiredCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositorySetIsProjectAccessRequiredCall) DoAndReturn(f func(bool) database.Change) *MockProjectRepositorySetIsProjectAccessRequiredCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetName mocks base method. +func (m *MockProjectRepository) SetName(name string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetName", name) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetName indicates an expected call of SetName. +func (mr *MockProjectRepositoryMockRecorder) SetName(name any) *MockProjectRepositorySetNameCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetName", reflect.TypeOf((*MockProjectRepository)(nil).SetName), name) + return &MockProjectRepositorySetNameCall{Call: call} +} + +// MockProjectRepositorySetNameCall wrap *gomock.Call +type MockProjectRepositorySetNameCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositorySetNameCall) Return(arg0 database.Change) *MockProjectRepositorySetNameCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositorySetNameCall) Do(f func(string) database.Change) *MockProjectRepositorySetNameCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositorySetNameCall) DoAndReturn(f func(string) database.Change) *MockProjectRepositorySetNameCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetShouldAssertRole mocks base method. +func (m *MockProjectRepository) SetShouldAssertRole(shouldAssertRole bool) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetShouldAssertRole", shouldAssertRole) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetShouldAssertRole indicates an expected call of SetShouldAssertRole. +func (mr *MockProjectRepositoryMockRecorder) SetShouldAssertRole(shouldAssertRole any) *MockProjectRepositorySetShouldAssertRoleCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetShouldAssertRole", reflect.TypeOf((*MockProjectRepository)(nil).SetShouldAssertRole), shouldAssertRole) + return &MockProjectRepositorySetShouldAssertRoleCall{Call: call} +} + +// MockProjectRepositorySetShouldAssertRoleCall wrap *gomock.Call +type MockProjectRepositorySetShouldAssertRoleCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositorySetShouldAssertRoleCall) Return(arg0 database.Change) *MockProjectRepositorySetShouldAssertRoleCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositorySetShouldAssertRoleCall) Do(f func(bool) database.Change) *MockProjectRepositorySetShouldAssertRoleCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositorySetShouldAssertRoleCall) DoAndReturn(f func(bool) database.Change) *MockProjectRepositorySetShouldAssertRoleCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetState mocks base method. +func (m *MockProjectRepository) SetState(state domain.ProjectState) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetState", state) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetState indicates an expected call of SetState. +func (mr *MockProjectRepositoryMockRecorder) SetState(state any) *MockProjectRepositorySetStateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetState", reflect.TypeOf((*MockProjectRepository)(nil).SetState), state) + return &MockProjectRepositorySetStateCall{Call: call} +} + +// MockProjectRepositorySetStateCall wrap *gomock.Call +type MockProjectRepositorySetStateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositorySetStateCall) Return(arg0 database.Change) *MockProjectRepositorySetStateCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositorySetStateCall) Do(f func(domain.ProjectState) database.Change) *MockProjectRepositorySetStateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositorySetStateCall) DoAndReturn(f func(domain.ProjectState) database.Change) *MockProjectRepositorySetStateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetUpdatedAt mocks base method. +func (m *MockProjectRepository) SetUpdatedAt(updatedAt time.Time) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUpdatedAt", updatedAt) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetUpdatedAt indicates an expected call of SetUpdatedAt. +func (mr *MockProjectRepositoryMockRecorder) SetUpdatedAt(updatedAt any) *MockProjectRepositorySetUpdatedAtCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUpdatedAt", reflect.TypeOf((*MockProjectRepository)(nil).SetUpdatedAt), updatedAt) + return &MockProjectRepositorySetUpdatedAtCall{Call: call} +} + +// MockProjectRepositorySetUpdatedAtCall wrap *gomock.Call +type MockProjectRepositorySetUpdatedAtCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositorySetUpdatedAtCall) Return(arg0 database.Change) *MockProjectRepositorySetUpdatedAtCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositorySetUpdatedAtCall) Do(f func(time.Time) database.Change) *MockProjectRepositorySetUpdatedAtCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositorySetUpdatedAtCall) DoAndReturn(f func(time.Time) database.Change) *MockProjectRepositorySetUpdatedAtCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetUsedLabelingSettingOwner mocks base method. +func (m *MockProjectRepository) SetUsedLabelingSettingOwner(usedLabelingSettingOwner int16) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUsedLabelingSettingOwner", usedLabelingSettingOwner) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetUsedLabelingSettingOwner indicates an expected call of SetUsedLabelingSettingOwner. +func (mr *MockProjectRepositoryMockRecorder) SetUsedLabelingSettingOwner(usedLabelingSettingOwner any) *MockProjectRepositorySetUsedLabelingSettingOwnerCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUsedLabelingSettingOwner", reflect.TypeOf((*MockProjectRepository)(nil).SetUsedLabelingSettingOwner), usedLabelingSettingOwner) + return &MockProjectRepositorySetUsedLabelingSettingOwnerCall{Call: call} +} + +// MockProjectRepositorySetUsedLabelingSettingOwnerCall wrap *gomock.Call +type MockProjectRepositorySetUsedLabelingSettingOwnerCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositorySetUsedLabelingSettingOwnerCall) Return(arg0 database.Change) *MockProjectRepositorySetUsedLabelingSettingOwnerCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositorySetUsedLabelingSettingOwnerCall) Do(f func(int16) database.Change) *MockProjectRepositorySetUsedLabelingSettingOwnerCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositorySetUsedLabelingSettingOwnerCall) DoAndReturn(f func(int16) database.Change) *MockProjectRepositorySetUsedLabelingSettingOwnerCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ShouldAssertRoleColumn mocks base method. +func (m *MockProjectRepository) ShouldAssertRoleColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ShouldAssertRoleColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// ShouldAssertRoleColumn indicates an expected call of ShouldAssertRoleColumn. +func (mr *MockProjectRepositoryMockRecorder) ShouldAssertRoleColumn() *MockProjectRepositoryShouldAssertRoleColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ShouldAssertRoleColumn", reflect.TypeOf((*MockProjectRepository)(nil).ShouldAssertRoleColumn)) + return &MockProjectRepositoryShouldAssertRoleColumnCall{Call: call} +} + +// MockProjectRepositoryShouldAssertRoleColumnCall wrap *gomock.Call +type MockProjectRepositoryShouldAssertRoleColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryShouldAssertRoleColumnCall) Return(arg0 database.Column) *MockProjectRepositoryShouldAssertRoleColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryShouldAssertRoleColumnCall) Do(f func() database.Column) *MockProjectRepositoryShouldAssertRoleColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryShouldAssertRoleColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryShouldAssertRoleColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// StateColumn mocks base method. +func (m *MockProjectRepository) StateColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// StateColumn indicates an expected call of StateColumn. +func (mr *MockProjectRepositoryMockRecorder) StateColumn() *MockProjectRepositoryStateColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateColumn", reflect.TypeOf((*MockProjectRepository)(nil).StateColumn)) + return &MockProjectRepositoryStateColumnCall{Call: call} +} + +// MockProjectRepositoryStateColumnCall wrap *gomock.Call +type MockProjectRepositoryStateColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryStateColumnCall) Return(arg0 database.Column) *MockProjectRepositoryStateColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryStateColumnCall) Do(f func() database.Column) *MockProjectRepositoryStateColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryStateColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryStateColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// StateCondition mocks base method. +func (m *MockProjectRepository) StateCondition(state domain.ProjectState) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateCondition", state) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// StateCondition indicates an expected call of StateCondition. +func (mr *MockProjectRepositoryMockRecorder) StateCondition(state any) *MockProjectRepositoryStateConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateCondition", reflect.TypeOf((*MockProjectRepository)(nil).StateCondition), state) + return &MockProjectRepositoryStateConditionCall{Call: call} +} + +// MockProjectRepositoryStateConditionCall wrap *gomock.Call +type MockProjectRepositoryStateConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryStateConditionCall) Return(arg0 database.Condition) *MockProjectRepositoryStateConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryStateConditionCall) Do(f func(domain.ProjectState) database.Condition) *MockProjectRepositoryStateConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryStateConditionCall) DoAndReturn(f func(domain.ProjectState) database.Condition) *MockProjectRepositoryStateConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Update mocks base method. +func (m *MockProjectRepository) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client, condition} + for _, a := range changes { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Update", varargs...) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockProjectRepositoryMockRecorder) Update(ctx, client, condition any, changes ...any) *MockProjectRepositoryUpdateCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client, condition}, changes...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockProjectRepository)(nil).Update), varargs...) + return &MockProjectRepositoryUpdateCall{Call: call} +} + +// MockProjectRepositoryUpdateCall wrap *gomock.Call +type MockProjectRepositoryUpdateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryUpdateCall) Return(arg0 int64, arg1 error) *MockProjectRepositoryUpdateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryUpdateCall) Do(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockProjectRepositoryUpdateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryUpdateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockProjectRepositoryUpdateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdatedAtColumn mocks base method. +func (m *MockProjectRepository) UpdatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// UpdatedAtColumn indicates an expected call of UpdatedAtColumn. +func (mr *MockProjectRepositoryMockRecorder) UpdatedAtColumn() *MockProjectRepositoryUpdatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtColumn", reflect.TypeOf((*MockProjectRepository)(nil).UpdatedAtColumn)) + return &MockProjectRepositoryUpdatedAtColumnCall{Call: call} +} + +// MockProjectRepositoryUpdatedAtColumnCall wrap *gomock.Call +type MockProjectRepositoryUpdatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryUpdatedAtColumnCall) Return(arg0 database.Column) *MockProjectRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryUpdatedAtColumnCall) Do(f func() database.Column) *MockProjectRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryUpdatedAtColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryUpdatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UsedLabelingSettingOwnerColumn mocks base method. +func (m *MockProjectRepository) UsedLabelingSettingOwnerColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UsedLabelingSettingOwnerColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// UsedLabelingSettingOwnerColumn indicates an expected call of UsedLabelingSettingOwnerColumn. +func (mr *MockProjectRepositoryMockRecorder) UsedLabelingSettingOwnerColumn() *MockProjectRepositoryUsedLabelingSettingOwnerColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UsedLabelingSettingOwnerColumn", reflect.TypeOf((*MockProjectRepository)(nil).UsedLabelingSettingOwnerColumn)) + return &MockProjectRepositoryUsedLabelingSettingOwnerColumnCall{Call: call} +} + +// MockProjectRepositoryUsedLabelingSettingOwnerColumnCall wrap *gomock.Call +type MockProjectRepositoryUsedLabelingSettingOwnerColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockProjectRepositoryUsedLabelingSettingOwnerColumnCall) Return(arg0 database.Column) *MockProjectRepositoryUsedLabelingSettingOwnerColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockProjectRepositoryUsedLabelingSettingOwnerColumnCall) Do(f func() database.Column) *MockProjectRepositoryUsedLabelingSettingOwnerColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockProjectRepositoryUsedLabelingSettingOwnerColumnCall) DoAndReturn(f func() database.Column) *MockProjectRepositoryUsedLabelingSettingOwnerColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/backend/v3/domain/mock/project_repo.go b/backend/v3/domain/mock/project_repo.go new file mode 100644 index 000000000..43bf6338f --- /dev/null +++ b/backend/v3/domain/mock/project_repo.go @@ -0,0 +1,47 @@ +package domainmock + +import ( + context "context" + + gomock "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + database "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/repository" +) + +func NewProjectRepo(ctrl *gomock.Controller) *ProjectRepo { + return &ProjectRepo{ + mock: NewMockProjectRepository(ctrl), + ProjectRepository: repository.ProjectRepository(), + } +} + +type ProjectRepo struct { + domain.ProjectRepository + mock *MockProjectRepository +} + +func (r *ProjectRepo) EXPECT() *MockProjectRepositoryMockRecorder { + return r.mock.EXPECT() +} + +func (r *ProjectRepo) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Project, error) { + return r.mock.Get(ctx, client, opts...) +} + +func (r *ProjectRepo) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.Project, error) { + return r.mock.List(ctx, client, opts...) +} + +func (r *ProjectRepo) Create(ctx context.Context, client database.QueryExecutor, org *domain.Project) error { + return r.mock.Create(ctx, client, org) +} + +func (r *ProjectRepo) Update(ctx context.Context, client database.QueryExecutor, conditions database.Condition, changes ...database.Change) (int64, error) { + return r.mock.Update(ctx, client, conditions, changes...) +} + +func (r *ProjectRepo) Delete(ctx context.Context, client database.QueryExecutor, conditions database.Condition) (int64, error) { + return r.mock.Delete(ctx, client, conditions) +} diff --git a/backend/v3/domain/mock/querier.mock.go b/backend/v3/domain/mock/querier.mock.go new file mode 100644 index 000000000..ec9a02613 --- /dev/null +++ b/backend/v3/domain/mock/querier.mock.go @@ -0,0 +1,194 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/zitadel/zitadel/backend/v3/domain (interfaces: Querier) +// +// Generated by this command: +// +// mockgen -typed -package domainmock -destination ./mock/querier.mock.go . Querier +// + +// Package domainmock is a generated GoMock package. +package domainmock + +import ( + context "context" + reflect "reflect" + + domain "github.com/zitadel/zitadel/backend/v3/domain" + gomock "go.uber.org/mock/gomock" +) + +// MockQuerier is a mock of Querier interface. +type MockQuerier[T any] struct { + ctrl *gomock.Controller + recorder *MockQuerierMockRecorder[T] + isgomock struct{} +} + +// MockQuerierMockRecorder is the mock recorder for MockQuerier. +type MockQuerierMockRecorder[T any] struct { + mock *MockQuerier[T] +} + +// NewMockQuerier creates a new mock instance. +func NewMockQuerier[T any](ctrl *gomock.Controller) *MockQuerier[T] { + mock := &MockQuerier[T]{ctrl: ctrl} + mock.recorder = &MockQuerierMockRecorder[T]{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockQuerier[T]) EXPECT() *MockQuerierMockRecorder[T] { + return m.recorder +} + +// Execute mocks base method. +func (m *MockQuerier[T]) Execute(ctx context.Context, opts *domain.InvokeOpts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Execute", ctx, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// Execute indicates an expected call of Execute. +func (mr *MockQuerierMockRecorder[T]) Execute(ctx, opts any) *MockQuerierExecuteCall[T] { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockQuerier[T])(nil).Execute), ctx, opts) + return &MockQuerierExecuteCall[T]{Call: call} +} + +// MockQuerierExecuteCall wrap *gomock.Call +type MockQuerierExecuteCall[T any] struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockQuerierExecuteCall[T]) Return(err error) *MockQuerierExecuteCall[T] { + c.Call = c.Call.Return(err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockQuerierExecuteCall[T]) Do(f func(context.Context, *domain.InvokeOpts) error) *MockQuerierExecuteCall[T] { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockQuerierExecuteCall[T]) DoAndReturn(f func(context.Context, *domain.InvokeOpts) error) *MockQuerierExecuteCall[T] { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Result mocks base method. +func (m *MockQuerier[T]) Result() T { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Result") + ret0, _ := ret[0].(T) + return ret0 +} + +// Result indicates an expected call of Result. +func (mr *MockQuerierMockRecorder[T]) Result() *MockQuerierResultCall[T] { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Result", reflect.TypeOf((*MockQuerier[T])(nil).Result)) + return &MockQuerierResultCall[T]{Call: call} +} + +// MockQuerierResultCall wrap *gomock.Call +type MockQuerierResultCall[T any] struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockQuerierResultCall[T]) Return(arg0 T) *MockQuerierResultCall[T] { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockQuerierResultCall[T]) Do(f func() T) *MockQuerierResultCall[T] { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockQuerierResultCall[T]) DoAndReturn(f func() T) *MockQuerierResultCall[T] { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// String mocks base method. +func (m *MockQuerier[T]) String() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "String") + ret0, _ := ret[0].(string) + return ret0 +} + +// String indicates an expected call of String. +func (mr *MockQuerierMockRecorder[T]) String() *MockQuerierStringCall[T] { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockQuerier[T])(nil).String)) + return &MockQuerierStringCall[T]{Call: call} +} + +// MockQuerierStringCall wrap *gomock.Call +type MockQuerierStringCall[T any] struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockQuerierStringCall[T]) Return(arg0 string) *MockQuerierStringCall[T] { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockQuerierStringCall[T]) Do(f func() string) *MockQuerierStringCall[T] { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockQuerierStringCall[T]) DoAndReturn(f func() string) *MockQuerierStringCall[T] { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Validate mocks base method. +func (m *MockQuerier[T]) Validate(ctx context.Context, opts *domain.InvokeOpts) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validate", ctx, opts) + ret0, _ := ret[0].(error) + return ret0 +} + +// Validate indicates an expected call of Validate. +func (mr *MockQuerierMockRecorder[T]) Validate(ctx, opts any) *MockQuerierValidateCall[T] { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockQuerier[T])(nil).Validate), ctx, opts) + return &MockQuerierValidateCall[T]{Call: call} +} + +// MockQuerierValidateCall wrap *gomock.Call +type MockQuerierValidateCall[T any] struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockQuerierValidateCall[T]) Return(err error) *MockQuerierValidateCall[T] { + c.Call = c.Call.Return(err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockQuerierValidateCall[T]) Do(f func(context.Context, *domain.InvokeOpts) error) *MockQuerierValidateCall[T] { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockQuerierValidateCall[T]) DoAndReturn(f func(context.Context, *domain.InvokeOpts) error) *MockQuerierValidateCall[T] { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/backend/v3/domain/org_activate.go b/backend/v3/domain/org_activate.go new file mode 100644 index 000000000..6e75caf68 --- /dev/null +++ b/backend/v3/domain/org_activate.go @@ -0,0 +1,98 @@ +package domain + +import ( + "context" + "errors" + "strings" + + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/zerrors" +) + +var _ Commander = (*ActivateOrgCommand)(nil) + +type ActivateOrgCommand struct { + ID string `json:"id"` +} + +func NewActivateOrgCommand(organizationID string) *ActivateOrgCommand { + return &ActivateOrgCommand{ID: organizationID} +} + +// Events implements [Commander]. +func (d *ActivateOrgCommand) Events(ctx context.Context, opts *InvokeOpts) ([]eventstore.Command, error) { + return []eventstore.Command{org.NewOrgReactivatedEvent(ctx, &org.NewAggregate(d.ID).Aggregate)}, nil +} + +// Execute implements [Commander]. +func (d *ActivateOrgCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + close, err := opts.EnsureTx(ctx) + if err != nil { + return err + } + defer func() { err = close(ctx, err) }() + + organizationRepo := opts.organizationRepo + + updateCount, err := organizationRepo.Update(ctx, pool, + database.And( + organizationRepo.IDCondition(d.ID), + organizationRepo.InstanceIDCondition(authz.GetInstance(ctx).InstanceID()), + ), + database.NewChange(organizationRepo.StateColumn(), OrgStateActive), + ) + + if err != nil { + return err + } + + if updateCount == 0 { + err = zerrors.ThrowNotFound(nil, "DOM-CGumXG", "Errors.Org.NotFound") + return err + } + if updateCount > 1 { + err = zerrors.ThrowInternal(NewMultipleObjectsUpdatedError(1, updateCount), "DOM-SEWCLp", "unexpected number of rows updated") + return err + } + + return nil +} + +// String implements [Commander]. +func (d *ActivateOrgCommand) String() string { + return "ActivateOrgCommand" +} + +// Validate implements [Commander]. +func (d *ActivateOrgCommand) Validate(ctx context.Context, opts *InvokeOpts) (err error) { + if d.ID = strings.TrimSpace(d.ID); d.ID == "" { + return zerrors.ThrowInvalidArgument(nil, "DOM-hJuuAv", "invalid organization ID") + } + + organizationRepo := opts.organizationRepo + + // TODO: lock entry as soon as https://github.com/zitadel/zitadel/issues/10930 is done + org, err := organizationRepo.Get(ctx, pool, database.WithCondition( + database.And( + organizationRepo.IDCondition(d.ID), + organizationRepo.InstanceIDCondition(authz.GetInstance(ctx).InstanceID()), + ), + )) + if err != nil { + var notFoundError *database.NoRowFoundError + if errors.As(err, ¬FoundError) { + err = zerrors.ThrowNotFound(err, "DOM-86HVfs", "Errors.Org.NotFound") + } + return err + } + + if org.State == OrgStateActive { + err = zerrors.ThrowPreconditionFailed(nil, "DOM-Ixfbxh", "Errors.Org.AlreadyActive") + return err + } + + return nil +} diff --git a/backend/v3/domain/org_activate_test.go b/backend/v3/domain/org_activate_test.go new file mode 100644 index 000000000..1b518b8da --- /dev/null +++ b/backend/v3/domain/org_activate_test.go @@ -0,0 +1,291 @@ +package domain_test + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + domainmock "github.com/zitadel/zitadel/backend/v3/domain/mock" + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/dbmock" + noopdb "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/noop" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/zerrors" +) + +func TestActivateOrgCommand_Events(t *testing.T) { + t.Parallel() + // Given + expected := []eventstore.Command{org.NewOrgReactivatedEvent(context.Background(), &org.NewAggregate("some-id").Aggregate)} + activateCmd := domain.NewActivateOrgCommand("some-id") + + // Test + actual, err := activateCmd.Events(context.Background(), &domain.InvokeOpts{}) + + // Verify + + require.NoError(t, err) + assert.Equal(t, expected, actual) +} + +func TestActivateOrgCommand_Validate(t *testing.T) { + t.Parallel() + getErr := errors.New("get error") + + tt := []struct { + testName string + inputOrgID string + + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + + expectedError error + }{ + { + testName: "empty org id", + expectedError: zerrors.ThrowInvalidArgument(nil, "DOM-hJuuAv", "invalid organization ID"), + }, + { + testName: "whitespace org id", + inputOrgID: " ", + expectedError: zerrors.ThrowInvalidArgument(nil, "DOM-hJuuAv", "invalid organization ID"), + }, + { + testName: "when retrieving org fails with generic error should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions( + database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(nil, getErr) + return repo + }, + inputOrgID: "org-1", + expectedError: getErr, + }, + { + testName: "when retrieving org fails with not found error should return not found error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions( + database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(nil, database.NewNoRowFoundError(getErr)) + return repo + }, + inputOrgID: "org-1", + expectedError: zerrors.ThrowNotFound(database.NewNoRowFoundError(getErr), "DOM-86HVfs", "Errors.Org.NotFound"), + }, + { + testName: "when org state is active should return already active error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + State: domain.OrgStateActive, + }, nil) + return repo + }, + inputOrgID: "org-1", + expectedError: zerrors.ThrowPreconditionFailed(nil, "DOM-Ixfbxh", "Errors.Org.AlreadyActive"), + }, + { + testName: "when org state inactive should successfully validate organization", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + State: domain.OrgStateInactive, + }, nil) + return repo + }, + inputOrgID: "org-1", + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + cmd := domain.NewActivateOrgCommand(tc.inputOrgID) + ctx := authz.NewMockContext("instance-1", "", "") + ctrl := gomock.NewController(t) + opts := &domain.InvokeOpts{ + DB: new(noopdb.Pool), + } + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + + // Test + err := cmd.Validate(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + }) + } +} + +func TestActivateOrgCommand_Execute(t *testing.T) { + t.Parallel() + txInitErr := errors.New("tx init error") + updateErr := errors.New("update error") + + tt := []struct { + testName string + + queryExecutor func(ctrl *gomock.Controller) database.QueryExecutor + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + + inputID string + + expectedError error + }{ + { + testName: "when EnsureTx fails should return error", + queryExecutor: func(ctrl *gomock.Controller) database.QueryExecutor { + mockDB := dbmock.NewMockPool(ctrl) + mockDB.EXPECT(). + Begin(gomock.Any(), gomock.Any()). + Times(1). + Return(nil, txInitErr) + return mockDB + }, + expectedError: txInitErr, + }, + { + testName: "when org update fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateActive), + ). + Times(1). + Return(int64(0), updateErr) + return repo + }, + inputID: "org-1", + expectedError: updateErr, + }, + { + testName: "when org update returns 0 rows updated should return not found error", + inputID: "org-1", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateActive)). + Times(1). + Return(int64(0), nil) + return repo + }, + expectedError: zerrors.ThrowNotFound(nil, "DOM-CGumXG", "Errors.Org.NotFound"), + }, + { + testName: "when org update returns more than 1 row updated should return internal error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateActive)). + Times(1). + Return(int64(2), nil) + return repo + }, + inputID: "org-1", + expectedError: zerrors.ThrowInternal(domain.NewMultipleObjectsUpdatedError(1, 2), "DOM-SEWCLp", "unexpected number of rows updated"), + }, + { + testName: "when org update returns 1 row updated should return no error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateActive)). + Times(1). + Return(int64(1), nil) + return repo + }, + inputID: "org-1", + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + ctx := authz.NewMockContext("instance-1", "", "") + ctrl := gomock.NewController(t) + cmd := &domain.ActivateOrgCommand{ + ID: tc.inputID, + } + + opts := &domain.InvokeOpts{ + DB: new(noopdb.Pool), + } + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + if tc.queryExecutor != nil { + opts.DB = tc.queryExecutor(ctrl) + } + + // Test + err := cmd.Execute(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + }) + } +} diff --git a/backend/v3/domain/org_deactivate.go b/backend/v3/domain/org_deactivate.go new file mode 100644 index 000000000..519ecca35 --- /dev/null +++ b/backend/v3/domain/org_deactivate.go @@ -0,0 +1,96 @@ +package domain + +import ( + "context" + "errors" + "strings" + + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/zerrors" +) + +var _ Commander = (*DeactivateOrgCommand)(nil) + +type DeactivateOrgCommand struct { + ID string `json:"id"` +} + +func NewDeactivateOrgCommand(organizationID string) *DeactivateOrgCommand { + return &DeactivateOrgCommand{ID: organizationID} +} + +// Events implements [Commander]. +func (d *DeactivateOrgCommand) Events(ctx context.Context, opts *InvokeOpts) ([]eventstore.Command, error) { + return []eventstore.Command{org.NewOrgDeactivatedEvent(ctx, &org.NewAggregate(d.ID).Aggregate)}, nil +} + +// Execute implements [Commander]. +func (d *DeactivateOrgCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + close, err := opts.EnsureTx(ctx) + if err != nil { + return err + } + defer func() { err = close(ctx, err) }() + + organizationRepo := opts.organizationRepo + + updateCount, err := organizationRepo.Update(ctx, pool, + database.And( + organizationRepo.IDCondition(d.ID), + organizationRepo.InstanceIDCondition(authz.GetInstance(ctx).InstanceID()), + ), + database.NewChange(organizationRepo.StateColumn(), OrgStateInactive), + ) + + if err != nil { + return err + } + + if updateCount == 0 { + err = zerrors.ThrowNotFound(nil, "DOM-vWPy7D", "Errors.Org.NotFound") + return err + } + if updateCount > 1 { + err = zerrors.ThrowInternal(NewMultipleObjectsUpdatedError(1, updateCount), "DOM-dXl1kJ", "unexpected number of rows updated") + return err + } + + return nil +} + +// String implements [Commander]. +func (d *DeactivateOrgCommand) String() string { + return "DeactivateOrgCommand" +} + +// Validate implements [Commander]. +func (d *DeactivateOrgCommand) Validate(ctx context.Context, opts *InvokeOpts) (err error) { + if d.ID = strings.TrimSpace(d.ID); d.ID == "" { + return zerrors.ThrowInvalidArgument(nil, "DOM-Qc3T1r", "invalid organization ID") + } + + organizationRepo := opts.organizationRepo + + org, err := organizationRepo.Get(ctx, pool, database.WithCondition( + database.And( + organizationRepo.IDCondition(d.ID), + organizationRepo.InstanceIDCondition(authz.GetInstance(ctx).InstanceID()), + ), + )) + if err != nil { + var notFoundError *database.NoRowFoundError + if errors.As(err, ¬FoundError) { + err = zerrors.ThrowNotFound(err, "DOM-QEjfpz", "Errors.Org.NotFound") + } + return err + } + + if org.State == OrgStateInactive { + err = zerrors.ThrowPreconditionFailed(nil, "DOM-Z2dzsT", "Errors.Org.AlreadyDeactivated") + return err + } + return nil +} diff --git a/backend/v3/domain/org_deactivate_test.go b/backend/v3/domain/org_deactivate_test.go new file mode 100644 index 000000000..5998e07f1 --- /dev/null +++ b/backend/v3/domain/org_deactivate_test.go @@ -0,0 +1,270 @@ +package domain_test + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + domainmock "github.com/zitadel/zitadel/backend/v3/domain/mock" + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/dbmock" + noopdb "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/noop" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/zerrors" +) + +func TestDeactivateOrgCommand_Events(t *testing.T) { + t.Parallel() + // Given + expected := []eventstore.Command{org.NewOrgDeactivatedEvent(context.Background(), &org.NewAggregate("some-id").Aggregate)} + deactivateCmd := domain.NewDeactivateOrgCommand("some-id") + + // Test + actual, err := deactivateCmd.Events(context.Background(), &domain.InvokeOpts{}) + + // Verify + + require.NoError(t, err) + assert.Equal(t, expected, actual) +} + +func TestDeactivateOrgCommand_Validate(t *testing.T) { + t.Parallel() + getErr := errors.New("get error") + + tt := []struct { + testName string + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + + inputOrgID string + expectedError error + }{ + { + testName: "empty org id", + expectedError: zerrors.ThrowInvalidArgument(nil, "DOM-Qc3T1r", "invalid organization ID"), + }, + { + testName: "whitespace org id", + inputOrgID: " ", + expectedError: zerrors.ThrowInvalidArgument(nil, "DOM-Qc3T1r", "invalid organization ID"), + }, + { + testName: "when retrieving org fails with generic error should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions( + database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(nil, getErr) + return repo + }, + inputOrgID: "org-1", + expectedError: getErr, + }, + { + testName: "when retrieving org fails with not found error should return not found error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions( + database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(nil, database.NewNoRowFoundError(getErr)) + return repo + }, + inputOrgID: "org-1", + expectedError: zerrors.ThrowNotFound(database.NewNoRowFoundError(getErr), "DOM-QEjfpz", "Errors.Org.NotFound"), + }, + { + testName: "when org state is inactive should return already inactive error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + State: domain.OrgStateInactive, + }, nil) + return repo + }, + inputOrgID: "org-1", + expectedError: zerrors.ThrowPreconditionFailed(nil, "DOM-Z2dzsT", "Errors.Org.AlreadyDeactivated"), + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + ctx := authz.NewMockContext("instance-1", "", "") + ctrl := gomock.NewController(t) + cmd := domain.NewDeactivateOrgCommand(tc.inputOrgID) + + opts := &domain.InvokeOpts{ + DB: new(noopdb.Pool), + } + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + + // Test + err := cmd.Validate(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + }) + } +} + +func TestDeactivateOrgCommand_Execute(t *testing.T) { + t.Parallel() + txInitErr := errors.New("tx init error") + updateErr := errors.New("update error") + + tt := []struct { + testName string + + queryExecutor func(ctrl *gomock.Controller) database.QueryExecutor + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + + inputID string + + expectedError error + }{ + { + testName: "when EnsureTx fails should return error", + queryExecutor: func(ctrl *gomock.Controller) database.QueryExecutor { + mockDB := dbmock.NewMockPool(ctrl) + mockDB.EXPECT(). + Begin(gomock.Any(), gomock.Any()). + Times(1). + Return(nil, txInitErr) + return mockDB + }, + expectedError: txInitErr, + }, + { + testName: "when org update fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateInactive), + ). + Times(1). + Return(int64(0), updateErr) + return repo + }, + inputID: "org-1", + expectedError: updateErr, + }, + { + testName: "when org update returns 0 rows updated should return not found error", + inputID: "org-1", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateInactive)). + Times(1). + Return(int64(0), nil) + return repo + }, + expectedError: zerrors.ThrowNotFound(nil, "DOM-vWPy7D", "Errors.Org.NotFound"), + }, + { + testName: "when org update returns more than 1 row updated should return internal error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateInactive)). + Times(1). + Return(int64(2), nil) + return repo + }, + inputID: "org-1", + expectedError: zerrors.ThrowInternal(domain.NewMultipleObjectsUpdatedError(1, 2), "DOM-dXl1kJ", "unexpected number of rows updated"), + }, + { + testName: "when org update returns 1 row updated should return no error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetState(domain.OrgStateInactive)). + Times(1). + Return(int64(1), nil) + return repo + }, + inputID: "org-1", + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + ctx := authz.NewMockContext("instance-1", "", "") + ctrl := gomock.NewController(t) + cmd := &domain.DeactivateOrgCommand{ + ID: tc.inputID, + } + + opts := &domain.InvokeOpts{ + DB: new(noopdb.Pool), + } + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + if tc.queryExecutor != nil { + opts.DB = tc.queryExecutor(ctrl) + } + + // Test + err := cmd.Execute(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + }) + } +} diff --git a/backend/v3/domain/org_delete.go b/backend/v3/domain/org_delete.go new file mode 100644 index 000000000..d347cc9bc --- /dev/null +++ b/backend/v3/domain/org_delete.go @@ -0,0 +1,192 @@ +package domain + +import ( + "context" + "errors" + "strings" + + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/api/authz" + internal_domain "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/zerrors" +) + +type DeleteOrgCommand struct { + OrganizationName string `json:"organization_name"` + Domains []*OrganizationDomain + ID string `json:"id"` +} + +func NewDeleteOrgCommand(organizationID string) *DeleteOrgCommand { + return &DeleteOrgCommand{ID: organizationID} +} + +// Events implements [Commander]. +// +// TODO(IAM-Marco): Finish implementation when policies, org settings, idp links and entities repositories +// are implemented +func (d *DeleteOrgCommand) Events(ctx context.Context, opts *InvokeOpts) ([]eventstore.Command, error) { + closeFunc, err := opts.EnsureTx(ctx) + if err != nil { + return nil, err + } + defer func() { err = closeFunc(ctx, err) }() + + usernames := []string{} + // userRepo := opts.usersRepo(pool) + // users, err := userRepo.List(ctx, database.WithCondition(opts.organizationRepo(pool).IDCondition(d.ID))) + // if err != nil { + // return nil, err + // } + // for _, u := range users { + // usernames = append(usernames, u.UserID) + // } + + // domainPolicyRepo := opts.domainPolicyRepo(pool) + // policy, err := domainPolicyRepo.Get(ctx, instanceID, d.ID) + // if err != nil { + // return nil, err + // } + + // orgSettingsRepo := opts.organizationSettingsRepo(pool) + // orgSettings, err := orgSettingsRepo.Get(ctx, d.ID) + // if err != nil { + // return nil, err + // } + // areUsernamesOrganizationScoped := policy.UserLoginMustBeDomain || orgSettings.UsernamesUnique + areUsernamesOrganizationScoped := false + + domainNames := make([]string, len(d.Domains)) + for i, domain := range d.Domains { + domainNames[i] = domain.Domain + } + + externalIDPLinks := []*internal_domain.UserIDPLink{} + // idpLinksRepo := opts.idpLinksRepo(pool) + // idpLinks, err := idpLinksRepo.List(ctx, d.ID) + // if err != nil { + // return nil, err + // } + // for _, link := range idpLinks { + // // Convert repo to internal_domain + // externalIDPLinks = append(externalIDPLinks, link) + // } + + samlEntityIDs := []string{} + // entityIDsRepo := opts.entityIDsRepo(pool) + // entityIDs, err := entityIDsRepo.List(ctx, d.ID) + // if err != nil { + // return nil, err + // } + // for _, ei := range entityIDs { + // samlEntityIDs = append(samlEntityIDs, ei.ID) + // } + + return []eventstore.Command{ + org.NewOrgRemovedEvent( + ctx, + &org.NewAggregate(d.ID).Aggregate, + d.OrganizationName, + usernames, + areUsernamesOrganizationScoped, + domainNames, + externalIDPLinks, + samlEntityIDs, + ), + }, nil +} + +// Execute implements [Commander]. +func (d *DeleteOrgCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + closeFunc, err := opts.EnsureTx(ctx) + if err != nil { + return err + } + + defer func() { err = closeFunc(ctx, err) }() + instance := authz.GetInstance(ctx) + + orgRepo := opts.organizationRepo.LoadDomains() + + orgToDelete, err := orgRepo.Get(ctx, pool, database.WithCondition(database.And( + orgRepo.IDCondition(d.ID), + orgRepo.InstanceIDCondition(instance.InstanceID()), + ))) + if err != nil { + return err + } + d.OrganizationName = orgToDelete.Name + d.Domains = orgToDelete.Domains + + deletedRows, err := orgRepo.Delete(ctx, pool, + database.And( + orgRepo.IDCondition(d.ID), + orgRepo.InstanceIDCondition(authz.GetInstance(ctx).InstanceID()), + ), + ) + if err != nil { + return err + } + + if deletedRows > 1 { + err = zerrors.ThrowInternalf(nil, "DOM-5cE9u6", "expecting 1 row deleted, got %d", deletedRows) + return err + } + + if deletedRows < 1 { + err = zerrors.ThrowNotFound(nil, "DOM-ur6Qyv", "organization not found") + } + return err +} + +// String implements [Commander]. +func (d *DeleteOrgCommand) String() string { + return "DeleteOrgCommand" +} + +// Validate implements [Commander]. +func (d *DeleteOrgCommand) Validate(ctx context.Context, opts *InvokeOpts) (err error) { + instance := authz.GetInstance(ctx) + + d.ID = strings.TrimSpace(d.ID) + if d.ID == instance.DefaultOrganisationID() { + return zerrors.ThrowPreconditionFailed(nil, "DOM-LCkE69", "Errors.Org.DefaultOrgNotDeletable") + } + + // Check if the ZITADEL project exists on the input organization + projectRepo := opts.projectRepo + _, getErr := projectRepo.Get(ctx, pool, + database.WithCondition(database.And( + projectRepo.IDCondition(instance.ProjectID()), + projectRepo.OrganizationIDCondition(d.ID), + projectRepo.InstanceIDCondition(instance.InstanceID()), + )), + ) + if getErr == nil { + return zerrors.ThrowPreconditionFailed(nil, "DOM-X7YXxC", "Errors.Org.ZitadelOrgNotDeletable") + } + // [database.NoRowFoundError] error means the project does not exist, return other errors in case it's not that + if !errors.Is(getErr, &database.NoRowFoundError{}) { + err = getErr + return err + } + + orgRepo := opts.organizationRepo + _, errGetOrg := orgRepo.Get(ctx, pool, + database.WithCondition(database.And( + orgRepo.IDCondition(d.ID), + orgRepo.InstanceIDCondition(instance.InstanceID()), + ))) + if errGetOrg != nil { + if errors.Is(errGetOrg, &database.NoRowFoundError{}) { + err = zerrors.ThrowNotFound(errGetOrg, "DOM-8KYOH3", "Errors.Org.NotFound") + } + return err + } + + return err +} + +var _ Commander = (*DeleteOrgCommand)(nil) diff --git a/backend/v3/domain/org_delete_test.go b/backend/v3/domain/org_delete_test.go new file mode 100644 index 000000000..796c7a325 --- /dev/null +++ b/backend/v3/domain/org_delete_test.go @@ -0,0 +1,503 @@ +package domain_test + +import ( + "errors" + "testing" + + "github.com/brianvoe/gofakeit/v6" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + domainmock "github.com/zitadel/zitadel/backend/v3/domain/mock" + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/dbmock" + noopdb "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/noop" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/zerrors" +) + +func TestDeleteOrgCommand_Validate(t *testing.T) { + t.Parallel() + ctx := authz.NewMockContext("inst-1", "org-default", gofakeit.UUID(), authz.WithMockProjectID("prj-1")) + getErr := errors.New("get error") + + tt := []struct { + testName string + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + projectRepo func(ctrl *gomock.Controller) domain.ProjectRepository + inputOrganizationID string + expectedError error + }{ + { + testName: "validate delete default org, precondition failed", + + inputOrganizationID: "org-default", + expectedError: zerrors.ThrowPreconditionFailed(nil, "DOM-LCkE69", "Errors.Org.DefaultOrgNotDeletable"), + }, + { + testName: "when fetching project fails with NON precondition error should return error", + inputOrganizationID: "org-1", + projectRepo: func(ctrl *gomock.Controller) domain.ProjectRepository { + repo := domainmock.NewProjectRepo(ctrl) + + repo.EXPECT().Get(gomock.Any(), gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("prj-1"), + repo.OrganizationIDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + ))). + Times(1). + Return(nil, getErr) + + return repo + }, + expectedError: getErr, + }, + { + testName: "when fetching project succeeds should return precondition failed error", + inputOrganizationID: "org-1", + projectRepo: func(ctrl *gomock.Controller) domain.ProjectRepository { + repo := domainmock.NewProjectRepo(ctrl) + + repo.EXPECT().Get(gomock.Any(), gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("prj-1"), + repo.OrganizationIDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + ))). + Times(1). + Return(&domain.Project{}, nil) + + return repo + }, + expectedError: zerrors.ThrowPreconditionFailed(nil, "DOM-X7YXxC", "Errors.Org.ZitadelOrgNotDeletable"), + }, + { + testName: "when fetching organization fails with not found error should return not found error", + projectRepo: func(ctrl *gomock.Controller) domain.ProjectRepository { + repo := domainmock.NewProjectRepo(ctrl) + + repo.EXPECT().Get(gomock.Any(), gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("prj-1"), + repo.OrganizationIDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + ))). + Times(1). + Return(nil, database.NewNoRowFoundError(getErr)) + + return repo + }, + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And(repo.IDCondition("org-1"), repo.InstanceIDCondition("inst-1")), + ))). + Times(1). + Return(nil, database.NewNoRowFoundError(getErr)) + return repo + }, + inputOrganizationID: "org-1", + expectedError: zerrors.ThrowNotFound(database.NewNoRowFoundError(getErr), "DOM-8KYOH3", "Errors.Org.NotFound"), + }, + { + testName: "when organization is active should validate successfully", + projectRepo: func(ctrl *gomock.Controller) domain.ProjectRepository { + repo := domainmock.NewProjectRepo(ctrl) + + repo.EXPECT().Get(gomock.Any(), gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("prj-1"), + repo.OrganizationIDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + ))). + Times(1). + Return(nil, database.NewNoRowFoundError(getErr)) + + return repo + }, + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And(repo.IDCondition("org-1"), repo.InstanceIDCondition("inst-1")), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + State: domain.OrgStateActive, + }, nil) + return repo + }, + inputOrganizationID: "org-1", + }, + { + testName: "when organization is inactive should validate successfully", + projectRepo: func(ctrl *gomock.Controller) domain.ProjectRepository { + repo := domainmock.NewProjectRepo(ctrl) + + repo.EXPECT().Get(gomock.Any(), gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("prj-1"), + repo.OrganizationIDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + ))). + Times(1). + Return(nil, database.NewNoRowFoundError(getErr)) + + return repo + }, + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And(repo.IDCondition("org-1"), repo.InstanceIDCondition("inst-1")), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + State: domain.OrgStateInactive, + }, nil) + return repo + }, + inputOrganizationID: "org-1", + }, + } + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + d := domain.NewDeleteOrgCommand(tc.inputOrganizationID) + ctrl := gomock.NewController(t) + opts := &domain.InvokeOpts{DB: new(noopdb.Pool)} + + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + if tc.projectRepo != nil { + domain.WithProjectRepo(tc.projectRepo(ctrl))(opts) + } + + // Test + err := d.Validate(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + }) + } +} + +func TestDeleteOrgCommand_Execute(t *testing.T) { + t.Parallel() + + ctx := authz.NewMockContext("inst-1", "org-1", gofakeit.UUID()) + txInitErr := errors.New("tx init error") + deleteErr := errors.New("delete error") + getErr := errors.New("get error") + + tt := []struct { + testName string + mockTx func(ctrl *gomock.Controller) database.QueryExecutor + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + + inputOrganizationID string + + expectedError error + expectedOrgName string + }{ + { + testName: "when EnsureTx fails should return error", + mockTx: func(ctrl *gomock.Controller) database.QueryExecutor { + mockDB := dbmock.NewMockPool(ctrl) + mockDB.EXPECT(). + Begin(gomock.Any(), gomock.Any()). + Times(1). + Return(nil, txInitErr) + return mockDB + }, + expectedError: txInitErr, + }, + { + testName: "when retrieving organization fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + + repo.EXPECT(). + Get( + gomock.Any(), + gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + )), + ). + Times(1). + Return(nil, getErr) + return repo + }, + inputOrganizationID: "org-1", + expectedError: getErr, + }, + { + testName: "when delete organization fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + + repo.EXPECT(). + Get( + gomock.Any(), + gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + )), + ). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "organization 1", + }, nil) + repo.EXPECT(). + Delete(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1")), + ). + Times(1). + Return(int64(0), deleteErr) + return repo + }, + inputOrganizationID: "org-1", + expectedError: deleteErr, + expectedOrgName: "organization 1", + }, + { + testName: "when more than one row deleted should return internal error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + + repo.EXPECT(). + Get( + gomock.Any(), + gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + )), + ). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "organization 1", + }, nil) + repo.EXPECT(). + Delete(gomock.Any(), gomock.Any(), database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1")), + ). + Times(1). + Return(int64(2), nil) + return repo + }, + inputOrganizationID: "org-1", + expectedError: zerrors.ThrowInternalf(nil, "DOM-5cE9u6", "expecting 1 row deleted, got %d", 2), + expectedOrgName: "organization 1", + }, + { + testName: "when no rows deleted should return not found error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + + repo.EXPECT(). + Get( + gomock.Any(), + gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + )), + ). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "organization 1", + }, nil) + repo.EXPECT(). + Delete(gomock.Any(), gomock.Any(), database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1")), + ). + Times(1). + Return(int64(0), nil) + return repo + }, + inputOrganizationID: "org-1", + expectedError: zerrors.ThrowNotFoundf(nil, "DOM-ur6Qyv", "organization not found"), + expectedOrgName: "organization 1", + }, + { + testName: "when one row deleted should execute successfully", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + + repo.EXPECT(). + Get( + gomock.Any(), + gomock.Any(), + dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1"), + ), + )), + ). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "organization 1", + }, nil) + repo.EXPECT(). + Delete(gomock.Any(), gomock.Any(), database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("inst-1")), + ). + Times(1). + Return(int64(1), nil) + return repo + }, + inputOrganizationID: "org-1", + expectedOrgName: "organization 1", + }, + } + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + d := domain.NewDeleteOrgCommand(tc.inputOrganizationID) + ctrl := gomock.NewController(t) + opts := &domain.InvokeOpts{DB: new(noopdb.Pool)} + + if tc.mockTx != nil { + opts.DB = tc.mockTx(ctrl) + } + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + + // Test + err := d.Execute(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + assert.Equal(t, tc.expectedOrgName, d.OrganizationName) + }) + } +} + +// TODO(IAM-Marco): Expand these tests once the needed repositories (policies, org settings, idp links and entities) are available +func TestDeleteOrgCommand_Events(t *testing.T) { + t.Parallel() + ctx := authz.NewMockContext("inst-1", "org-1", gofakeit.UUID()) + txInitErr := errors.New("tx init error") + + tt := []struct { + testName string + mockTx func(ctrl *gomock.Controller) database.QueryExecutor + command *domain.DeleteOrgCommand + expectedError error + expectedCount int + }{ + { + testName: "when EnsureTx fails should return error", + mockTx: func(ctrl *gomock.Controller) database.QueryExecutor { + mockDB := dbmock.NewMockPool(ctrl) + mockDB.EXPECT(). + Begin(gomock.Any(), gomock.Any()). + Times(1). + Return(nil, txInitErr) + return mockDB + }, + command: domain.NewDeleteOrgCommand("org-1"), + expectedError: txInitErr, + }, + { + testName: "should create org removed event", + command: &domain.DeleteOrgCommand{ + ID: "org-1", + OrganizationName: "org name", + Domains: []*domain.OrganizationDomain{ + {Domain: "domain1.com"}, + {Domain: "domain2.com"}, + }, + }, + expectedCount: 1, + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + + // Given + ctrl := gomock.NewController(t) + opts := &domain.InvokeOpts{DB: new(noopdb.Pool)} + + if tc.mockTx != nil { + opts.DB = tc.mockTx(ctrl) + } + + // Test + cmds, err := tc.command.Events(ctx, opts) + + // Verify + require.Equal(t, tc.expectedError, err) + assert.Len(t, cmds, tc.expectedCount) + }) + } +} diff --git a/backend/v3/domain/org_domain_add.go b/backend/v3/domain/org_domain_add.go new file mode 100644 index 000000000..508e75c3d --- /dev/null +++ b/backend/v3/domain/org_domain_add.go @@ -0,0 +1,47 @@ +package domain + +import ( + "context" + + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" +) + +type AddOrgDomainCommand struct { + OrgID string `json:"org_id"` + Name string `json:"name"` + // ClaimedUserIDs []string `json:"claimed_user_ids"` +} + +// Events implements Commander. +func (a *AddOrgDomainCommand) Events(ctx context.Context, opts *InvokeOpts) ([]eventstore.Command, error) { + // TODO(IAM-Marco) Finish implementation in https://github.com/zitadel/zitadel/issues/10447 + return []eventstore.Command{ + org.NewDomainAddedEvent(ctx, &org.NewAggregate(a.OrgID).Aggregate, a.Name), + org.NewDomainVerifiedEvent(ctx, &org.NewAggregate(a.OrgID).Aggregate, a.Name), + }, nil +} + +func NewAddOrgDomainCommand(orgID, domainName string) *AddOrgDomainCommand { + return &AddOrgDomainCommand{ + OrgID: orgID, + Name: domainName, + } +} + +// Execute implements Commander. +func (a *AddOrgDomainCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + return nil +} + +// String implements Commander. +func (a *AddOrgDomainCommand) String() string { + return "AddOrgDomainCommand" +} + +// Validate implements Commander. +func (a *AddOrgDomainCommand) Validate(ctx context.Context, opts *InvokeOpts) (err error) { + return nil +} + +var _ Commander = (*AddOrgDomainCommand)(nil) diff --git a/backend/v3/domain/org_domain_remove.go b/backend/v3/domain/org_domain_remove.go new file mode 100644 index 000000000..e19bd35b3 --- /dev/null +++ b/backend/v3/domain/org_domain_remove.go @@ -0,0 +1,56 @@ +package domain + +import ( + "context" + + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" +) + +type RemoveOrgDomainCommand struct { + OrgID string `json:"org_id"` + Name *string `json:"name"` + IsVerified *bool `json:"is_verified"` +} + +// Events implements Commander. +func (r *RemoveOrgDomainCommand) Events(ctx context.Context, opts *InvokeOpts) ([]eventstore.Command, error) { + // TODO(IAM-Marco) Finish implementation in https://github.com/zitadel/zitadel/issues/10447 + oldDomainName := "" + isVerified := false + if r.Name != nil { + oldDomainName = *r.Name + } + if r.IsVerified != nil { + isVerified = *r.IsVerified + } + + return []eventstore.Command{ + org.NewDomainRemovedEvent(ctx, &org.NewAggregate(r.OrgID).Aggregate, oldDomainName, isVerified), + }, nil +} + +func NewRemoveOrgDomainCommand(orgID string, domainName *string, isDomainVerified *bool) *RemoveOrgDomainCommand { + return &RemoveOrgDomainCommand{ + OrgID: orgID, + Name: domainName, + IsVerified: isDomainVerified, + } +} + +// Execute implements Commander. +func (r *RemoveOrgDomainCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + return nil +} + +// String implements Commander. +func (r *RemoveOrgDomainCommand) String() string { + return "RemoveOrgDomainCommand" +} + +// Validate implements Commander. +func (r *RemoveOrgDomainCommand) Validate(ctx context.Context, opts *InvokeOpts) (err error) { + return nil +} + +var _ Commander = (*RemoveOrgDomainCommand)(nil) diff --git a/backend/v3/domain/org_domain_set.go b/backend/v3/domain/org_domain_set.go new file mode 100644 index 000000000..3520ba44b --- /dev/null +++ b/backend/v3/domain/org_domain_set.go @@ -0,0 +1,45 @@ +package domain + +import ( + "context" + + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" +) + +type SetPrimaryOrgDomainCommand struct { + OrgID string `json:"org_id"` + Name string `json:"name"` +} + +// Events implements Commander. +func (a *SetPrimaryOrgDomainCommand) Events(ctx context.Context, opts *InvokeOpts) ([]eventstore.Command, error) { + // TODO(IAM-Marco) Finish implementation in https://github.com/zitadel/zitadel/issues/10447 + return []eventstore.Command{ + org.NewDomainPrimarySetEvent(ctx, &org.NewAggregate(a.OrgID).Aggregate, a.Name), + }, nil +} + +func NewSetPrimaryOrgDomainCommand(orgID, domainName string) *SetPrimaryOrgDomainCommand { + return &SetPrimaryOrgDomainCommand{ + OrgID: orgID, + Name: domainName, + } +} + +// Execute implements Commander. +func (a *SetPrimaryOrgDomainCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + return nil +} + +// String implements Commander. +func (a *SetPrimaryOrgDomainCommand) String() string { + return "SetPrimaryOrgDomainCommand" +} + +// Validate implements Commander. +func (a *SetPrimaryOrgDomainCommand) Validate(ctx context.Context, opts *InvokeOpts) (err error) { + return nil +} + +var _ Commander = (*SetPrimaryOrgDomainCommand)(nil) diff --git a/backend/v3/domain/org_list.go b/backend/v3/domain/org_list.go new file mode 100644 index 000000000..080d90097 --- /dev/null +++ b/backend/v3/domain/org_list.go @@ -0,0 +1,120 @@ +package domain + +import ( + "context" + + "github.com/zitadel/zitadel/backend/v3/api/object" + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/zerrors" + v2_org "github.com/zitadel/zitadel/pkg/grpc/org/v2" +) + +type ListOrgsQuery struct { + Request *v2_org.ListOrganizationsRequest + + result []*Organization +} + +// Result implements [Querier]. +func (l *ListOrgsQuery) Result() []*Organization { + return l.result +} + +func NewListOrgsQuery(inputRequest *v2_org.ListOrganizationsRequest) *ListOrgsQuery { + return &ListOrgsQuery{ + Request: inputRequest, + } +} + +// Execute implements [Querier]. +func (l *ListOrgsQuery) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + organizationRepo := opts.organizationRepo.LoadDomains() + domainRepo := opts.organizationDomainRepo + + sorting := l.Sorting(organizationRepo) + limit, pagination := l.Pagination() + conditions, condErr := l.conditions(ctx, organizationRepo, domainRepo) + if condErr != nil { + err = condErr + return err + } + + l.result, err = organizationRepo.List(ctx, pool, conditions, sorting, limit, pagination) + return err +} + +func (l *ListOrgsQuery) Sorting(orgRepo OrganizationRepository) database.QueryOption { + var sortingCol database.Column + switch l.Request.GetSortingColumn() { + case v2_org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME: + sortingCol = orgRepo.NameColumn() + case v2_org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_UNSPECIFIED: + fallthrough + default: + return func(opts *database.QueryOpts) {} + } + + orderDirection := database.OrderDirectionDesc + if l.Request.GetQuery().GetAsc() { + orderDirection = database.OrderDirectionAsc + } + + return database.WithOrderBy(orderDirection, sortingCol) +} + +func (l *ListOrgsQuery) Pagination() (database.QueryOption, database.QueryOption) { + return database.WithLimit(l.Request.GetQuery().GetLimit()), + database.WithOffset(uint32(l.Request.GetQuery().GetOffset())) +} + +func (l *ListOrgsQuery) conditions(ctx context.Context, orgRepo OrganizationRepository, domainRepo OrganizationDomainRepository) (database.QueryOption, error) { + conditions := make([]database.Condition, len(l.Request.GetQueries())) + instance := authz.GetInstance(ctx) + + for i, query := range l.Request.GetQueries() { + switch assertedType := query.GetQuery().(type) { + + case *v2_org.SearchQuery_DefaultQuery: + conditions[i] = orgRepo.IDCondition(instance.DefaultOrganisationID()) + case *v2_org.SearchQuery_DomainQuery: + method, err := object.TextQueryMethodToTextOperation(assertedType.DomainQuery.GetMethod()) + if err != nil { + return nil, err + } + + conditions[i] = database.And( + orgRepo.InstanceIDCondition(instance.InstanceID()), + orgRepo.ExistsDomain(domainRepo.DomainCondition(method, assertedType.DomainQuery.GetDomain())), + ) + case *v2_org.SearchQuery_IdQuery: + conditions[i] = orgRepo.IDCondition(assertedType.IdQuery.GetId()) + case *v2_org.SearchQuery_NameQuery: + method, err := object.TextQueryMethodToTextOperation(assertedType.NameQuery.GetMethod()) + if err != nil { + return nil, err + } + conditions[i] = orgRepo.NameCondition(method, assertedType.NameQuery.GetName()) + case *v2_org.SearchQuery_StateQuery: + conditions[i] = orgRepo.StateCondition(OrgState(assertedType.StateQuery.GetState())) + default: + return nil, zerrors.ThrowInvalidArgument(NewUnexpectedQueryTypeError(assertedType), "DOM-TCEzcr", "List.Query.Invalid") + } + } + + return database.WithCondition(database.And( + append(conditions, orgRepo.InstanceIDCondition(instance.InstanceID()))..., + )), nil +} + +// String implements [Querier]. +func (l *ListOrgsQuery) String() string { + return "ListOrgsQuery" +} + +// Validate implements [Querier]. +func (l *ListOrgsQuery) Validate(_ context.Context, _ *InvokeOpts) (err error) { + return nil +} + +var _ Querier[[]*Organization] = (*ListOrgsQuery)(nil) diff --git a/backend/v3/domain/org_list_test.go b/backend/v3/domain/org_list_test.go new file mode 100644 index 000000000..0634d6444 --- /dev/null +++ b/backend/v3/domain/org_list_test.go @@ -0,0 +1,337 @@ +package domain_test + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + domainmock "github.com/zitadel/zitadel/backend/v3/domain/mock" + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/dbmock" + noopdb "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/noop" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/zerrors" + "github.com/zitadel/zitadel/pkg/grpc/object/v2" + "github.com/zitadel/zitadel/pkg/grpc/org/v2" +) + +func TestListOrgsCommand_sorting(t *testing.T) { + t.Parallel() + tt := []struct { + name string + request *org.ListOrganizationsRequest + + expectedSortingDirection database.OrderDirection + expectedOrderBy database.Columns + }{ + { + name: "sorting by name desc", + request: &org.ListOrganizationsRequest{ + SortingColumn: org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME, + Query: &object.ListQuery{ + Asc: false, + }, + }, + + expectedSortingDirection: database.OrderDirectionDesc, + expectedOrderBy: database.Columns{database.NewColumn("organizations", "name")}, + }, + { + name: "sorting by name asc", + request: &org.ListOrganizationsRequest{ + SortingColumn: org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME, + Query: &object.ListQuery{ + Asc: true, + }, + }, + + expectedSortingDirection: database.OrderDirectionAsc, + expectedOrderBy: database.Columns{database.NewColumn("organizations", "name")}, + }, + { + name: "unspecified sorting", + request: &org.ListOrganizationsRequest{ + SortingColumn: org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_UNSPECIFIED, + }, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + // Given + ctrl := gomock.NewController(t) + orgRepo := domainmock.NewOrgRepo(ctrl) + l := &domain.ListOrgsQuery{ + Request: tc.request, + } + opts := &database.QueryOpts{} + + // Test + gotFunc := l.Sorting(orgRepo) + gotFunc(opts) + + // Verify + assert.Equal(t, tc.expectedOrderBy, opts.OrderBy) + assert.Equal(t, tc.expectedSortingDirection, opts.Ordering) + }) + } +} + +func TestListOrgsCommand_pagination(t *testing.T) { + t.Parallel() + tt := []struct { + name string + request *org.ListOrganizationsRequest + wantLimit uint64 + wantOffset uint32 + }{ + { + name: "pagination with limit and offset", + request: &org.ListOrganizationsRequest{ + Query: &object.ListQuery{ + Limit: 10, + Offset: 5, + }, + }, + wantLimit: 10, + wantOffset: 5, + }, + { + name: "pagination with zero values", + request: &org.ListOrganizationsRequest{ + Query: &object.ListQuery{ + Limit: 0, + Offset: 0, + }, + }, + wantLimit: 0, + wantOffset: 0, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + // Given + l := &domain.ListOrgsQuery{ + Request: tc.request, + } + opts := &database.QueryOpts{} + + // Test + limitFunc, offsetFunc := l.Pagination() + limitFunc(opts) + offsetFunc(opts) + + // Verify + assert.EqualValues(t, tc.wantLimit, opts.Limit) + assert.EqualValues(t, tc.wantOffset, opts.Offset) + }) + } +} + +func TestListOrgsCommand_Execute(t *testing.T) { + t.Parallel() + listErr := errors.New("list mock error") + + tt := []struct { + testName string + + repos func(ctrl *gomock.Controller, queryParams ...database.QueryOption) (domain.OrganizationRepository, domain.OrganizationDomainRepository) + + queryParams []database.QueryOption + inputRequest *org.ListOrganizationsRequest + + expectedOrganizations []*domain.Organization + expectedError error + }{ + { + testName: "when condition parsing fails should return error", + repos: func(ctrl *gomock.Controller, _ ...database.QueryOption) (domain.OrganizationRepository, domain.OrganizationDomainRepository) { + orgRepo := domainmock.NewOrgRepo(ctrl) + domainRepo := domainmock.NewOrgDomainRepo(ctrl) + orgRepo.EXPECT(). + LoadDomains(). + Times(1). + Return(orgRepo) + + return orgRepo, domainRepo + }, + inputRequest: &org.ListOrganizationsRequest{ + Queries: []*org.SearchQuery{{Query: &org.SearchQuery_DomainQuery{DomainQuery: &org.OrganizationDomainQuery{ + Domain: "some domain", + Method: object.TextQueryMethod(99)}}, + }, + }, + }, + expectedError: zerrors.ThrowInvalidArgument(nil, "OBJ-iBRBVe", "invalid text query method"), + }, + { + testName: "when listing orgs fails should return error", + repos: func(ctrl *gomock.Controller, queryParams ...database.QueryOption) (domain.OrganizationRepository, domain.OrganizationDomainRepository) { + orgRepo := domainmock.NewOrgRepo(ctrl) + domainRepo := domainmock.NewOrgDomainRepo(ctrl) + orgRepo.SetExistsDomain(database.Exists("domains", domainRepo.DomainCondition(database.TextOperationEqual, "some domain"))) + + orgRepo.EXPECT(). + LoadDomains(). + Times(1). + Return(orgRepo) + + orgRepo.EXPECT(). + List( + gomock.Any(), + gomock.Any(), + dbmock.QueryOptions( + database.WithCondition( + database.And( + database.And( + orgRepo.InstanceIDCondition("instance-1"), + orgRepo.ExistsDomain(domainRepo.DomainCondition(database.TextOperationEqual, "some domain")), + ), + orgRepo.InstanceIDCondition("instance-1"), + ), + ), + ), + + dbmock.QueryOptions(database.WithOrderBy(database.OrderDirectionAsc, orgRepo.NameColumn())), + dbmock.QueryOptions(database.WithLimit(2)), + dbmock.QueryOptions(database.WithOffset(1)), + ). + Times(1). + Return(nil, listErr) + + return orgRepo, domainRepo + }, + inputRequest: &org.ListOrganizationsRequest{ + Queries: []*org.SearchQuery{ + { + Query: &org.SearchQuery_DomainQuery{ + DomainQuery: &org.OrganizationDomainQuery{ + Domain: "some domain", + Method: object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS, + }, + }, + }, + }, + SortingColumn: org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME, + Query: &object.ListQuery{ + Asc: true, + Offset: 1, + Limit: 2, + }, + }, + + expectedError: listErr, + }, + { + testName: "when listing orgs succeeds should return expected organizations", + repos: func(ctrl *gomock.Controller, queryParams ...database.QueryOption) (domain.OrganizationRepository, domain.OrganizationDomainRepository) { + orgRepo := domainmock.NewOrgRepo(ctrl) + domainRepo := domainmock.NewOrgDomainRepo(ctrl) + + orgRepo.EXPECT(). + LoadDomains(). + Times(1). + Return(orgRepo) + + orgRepo.EXPECT(). + List( + gomock.Any(), + gomock.Any(), + dbmock.QueryOptions(database.WithCondition(database.And( + orgRepo.IDCondition("org-1"), + orgRepo.IDCondition("org-2"), + orgRepo.NameCondition(database.TextOperationEqual, "Named Org"), + orgRepo.StateCondition(domain.OrgStateActive), + orgRepo.InstanceIDCondition("instance-1"), + ))), + + dbmock.QueryOptions(database.WithOrderBy(database.OrderDirectionDesc, orgRepo.NameColumn())), + dbmock.QueryOptions(database.WithLimit(2)), + dbmock.QueryOptions(database.WithOffset(1)), + ). + Times(1). + Return([]*domain.Organization{ + {ID: "org-1"}, + {ID: "org-2"}, + }, nil) + + return orgRepo, domainRepo + }, + inputRequest: &org.ListOrganizationsRequest{ + Queries: []*org.SearchQuery{ + { + Query: &org.SearchQuery_DefaultQuery{ + DefaultQuery: &org.DefaultOrganizationQuery{}, + }, + }, + { + Query: &org.SearchQuery_IdQuery{ + IdQuery: &org.OrganizationIDQuery{ + Id: "org-2", + }, + }, + }, + { + Query: &org.SearchQuery_NameQuery{ + NameQuery: &org.OrganizationNameQuery{ + Name: "Named Org", + Method: object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS, + }, + }, + }, + { + Query: &org.SearchQuery_StateQuery{ + StateQuery: &org.OrganizationStateQuery{ + State: org.OrganizationState_ORGANIZATION_STATE_ACTIVE, + }, + }, + }, + }, + SortingColumn: org.OrganizationFieldName_ORGANIZATION_FIELD_NAME_NAME, + Query: &object.ListQuery{ + Asc: false, + Offset: 1, + Limit: 2, + }, + }, + + expectedOrganizations: []*domain.Organization{ + {ID: "org-1"}, + {ID: "org-2"}, + }, + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + ctx := authz.NewMockContext("instance-1", "org-1", "") + ctrl := gomock.NewController(t) + cmd := &domain.ListOrgsQuery{ + Request: tc.inputRequest, + } + opts := &domain.InvokeOpts{ + DB: new(noopdb.Pool), + } + if tc.repos != nil { + orgRepo, domainRepo := tc.repos(ctrl, tc.queryParams...) + domain.WithOrganizationRepo(orgRepo)(opts) + domain.WithOrganizationDomainRepo(domainRepo)(opts) + } + + // Test + err := cmd.Execute(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + assert.ElementsMatch(t, tc.expectedOrganizations, cmd.Result()) + }) + } +} diff --git a/backend/v3/domain/org_update.go b/backend/v3/domain/org_update.go new file mode 100644 index 000000000..8a074df8f --- /dev/null +++ b/backend/v3/domain/org_update.go @@ -0,0 +1,147 @@ +package domain + +import ( + "context" + "strings" + + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/internal/api/authz" + http_utils "github.com/zitadel/zitadel/internal/api/http" + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/org" + "github.com/zitadel/zitadel/internal/zerrors" +) + +type UpdateOrgCommand struct { + ID string `json:"id"` + Name string `json:"name"` + + OldDomainName *string `json:"old_name"` + IsOldDomainVerified *bool `json:"is_old_domain_primary"` +} + +// Events implements Commander. +func (u *UpdateOrgCommand) Events(ctx context.Context, opts *InvokeOpts) ([]eventstore.Command, error) { + toReturn := []eventstore.Command{} + + if u.OldDomainName != nil && *u.OldDomainName != u.Name { + toReturn = append(toReturn, org.NewOrgChangedEvent(ctx, &org.NewAggregate(u.ID).Aggregate, *u.OldDomainName, u.Name)) + } + + return toReturn, nil +} + +var _ Commander = (*UpdateOrgCommand)(nil) + +func NewUpdateOrgCommand(id, name string) *UpdateOrgCommand { + return &UpdateOrgCommand{ + ID: id, + Name: name, + } +} + +func (u *UpdateOrgCommand) Execute(ctx context.Context, opts *InvokeOpts) (err error) { + close, err := opts.EnsureTx(ctx) + if err != nil { + return err + } + defer func() { err = close(ctx, err) }() + + organizationRepo := opts.organizationRepo.LoadDomains() + + org, err := organizationRepo.Get(ctx, pool, database.WithCondition( + database.And( + organizationRepo.IDCondition(u.ID), + organizationRepo.InstanceIDCondition(authz.GetInstance(ctx).InstanceID()), + ), + )) + if err != nil { + return err + } + + err = u.setDomainInfos(ctx, org) + if err != nil { + return err + } + + updateCount, err := organizationRepo.Update( + ctx, + pool, + database.And( + organizationRepo.IDCondition(org.ID), + organizationRepo.InstanceIDCondition(org.InstanceID), + ), + database.NewChange(organizationRepo.NameColumn(), u.Name), + ) + if err != nil { + return err + } + + if updateCount == 0 { + err = zerrors.ThrowNotFound(nil, "DOM-7PfSUn", "Errors.Org.NotFound") + return err + } + if updateCount > 1 { + err = zerrors.ThrowInternal(NewMultipleObjectsUpdatedError(1, updateCount), "DOM-QzITrx", "unexpected number of rows updated") + return err + } + + return err +} + +func (u *UpdateOrgCommand) String() string { + return "UpdateOrgCommand" +} + +func (u *UpdateOrgCommand) Validate(ctx context.Context, opts *InvokeOpts) error { + if u.ID = strings.TrimSpace(u.ID); u.ID == "" { + return zerrors.ThrowInvalidArgument(nil, "DOM-lEMhVC", "invalid organization ID") + } + if u.Name = strings.TrimSpace(u.Name); u.Name == "" { + return zerrors.ThrowInvalidArgument(nil, "DOM-wfUntW", "invalid organization name") + } + + close, err := opts.EnsureTx(ctx) + if err != nil { + return err + } + defer func() { err = close(ctx, err) }() + + organizationRepo := opts.organizationRepo + + org, err := organizationRepo.Get(ctx, pool, database.WithCondition( + database.And( + organizationRepo.IDCondition(u.ID), + organizationRepo.InstanceIDCondition(authz.GetInstance(ctx).InstanceID()), + ), + )) + if err != nil { + return err + } + + if org.Name == u.Name { + err = zerrors.ThrowPreconditionFailed(nil, "DOM-nDzwIu", "Errors.Org.NotChanged") + return err + } + + return nil +} + +func (u *UpdateOrgCommand) setDomainInfos(ctx context.Context, org *Organization) error { + iamDomain := http_utils.DomainContext(ctx).RequestedDomain() + oldDomainName, err := domain.NewIAMDomainName(org.Name, iamDomain) + if err != nil { + return err + } + + for _, d := range org.Domains { + if d.Domain == oldDomainName && !d.IsPrimary { + u.IsOldDomainVerified = &d.IsVerified + u.OldDomainName = &d.Domain + return nil + } + } + + return nil +} diff --git a/backend/v3/domain/org_update_test.go b/backend/v3/domain/org_update_test.go new file mode 100644 index 000000000..5c2bfd60b --- /dev/null +++ b/backend/v3/domain/org_update_test.go @@ -0,0 +1,492 @@ +package domain_test + +import ( + "context" + "errors" + "testing" + + "github.com/muhlemmer/gu" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + "github.com/zitadel/zitadel/backend/v3/domain" + domainmock "github.com/zitadel/zitadel/backend/v3/domain/mock" + "github.com/zitadel/zitadel/backend/v3/storage/database" + "github.com/zitadel/zitadel/backend/v3/storage/database/dbmock" + noopdb "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/noop" + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/zerrors" +) + +func TestUpdateOrgCommand_Execute(t *testing.T) { + t.Parallel() + + txInitErr := errors.New("tx init error") + getErr := errors.New("get error") + updateErr := errors.New("update error") + + tt := []struct { + testName string + + queryExecutor func(ctrl *gomock.Controller) database.QueryExecutor + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + + inputID string + inputName string + + expectedError error + expectedOldDomainName *string + expectedDomainVerified *bool + }{ + { + testName: "when EnsureTx fails should return error", + queryExecutor: func(ctrl *gomock.Controller) database.QueryExecutor { + mockDB := dbmock.NewMockPool(ctrl) + mockDB.EXPECT(). + Begin(gomock.Any(), gomock.Any()). + Times(1). + Return(nil, txInitErr) + return mockDB + }, + expectedError: txInitErr, + }, + { + testName: "when retrieving org fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions( + database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(nil, getErr) + return repo + }, + inputID: "org-1", + inputName: "test org update", + expectedError: getErr, + }, + { + testName: "when setting domain info fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "", + State: domain.OrgStateActive, + Domains: []*domain.OrganizationDomain{ + {IsPrimary: true, IsVerified: true, Domain: "old org name"}, + {IsPrimary: false, IsVerified: true, Domain: "old org name"}, + {IsPrimary: false, IsVerified: true, Domain: "old primary org name"}, + }, + }, nil) + return repo + }, + inputID: "org-1", + inputName: "test org update", + expectedError: zerrors.ThrowInvalidArgument(nil, "ORG-RrfXY", "Errors.Org.Domain.EmptyString"), + }, + { + testName: "when org update fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "old org name", + InstanceID: "instance-1", + State: domain.OrgStateActive, + Domains: []*domain.OrganizationDomain{ + {IsPrimary: true, IsVerified: true, Domain: "old-org-name."}, + {IsPrimary: false, IsVerified: true, Domain: "old-org-name-2."}, + }, + }, nil) + + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetName("test org update"), + ). + Times(1). + Return(int64(0), updateErr) + return repo + }, + inputID: "org-1", + inputName: "test org update", + expectedError: updateErr, + }, + { + testName: "when org update returns 0 rows updated should return not found error", + inputID: "org-1", + inputName: "test org update", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "old org name", + InstanceID: "instance-1", + State: domain.OrgStateActive, + Domains: []*domain.OrganizationDomain{ + {IsPrimary: true, IsVerified: true, Domain: "old-org-name."}, + {IsPrimary: false, IsVerified: true, Domain: "old-org-name."}, + {IsPrimary: false, IsVerified: true, Domain: "old-org-name-2."}, + }, + }, nil) + + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetName("test org update")). + Times(1). + Return(int64(0), nil) + return repo + }, + expectedError: zerrors.ThrowNotFound(nil, "DOM-7PfSUn", "Errors.Org.NotFound"), + expectedOldDomainName: gu.Ptr("old-org-name."), + expectedDomainVerified: gu.Ptr(true), + }, + { + testName: "when org update returns more than 1 row updated should return internal error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "old org name", + InstanceID: "instance-1", + State: domain.OrgStateActive, + Domains: []*domain.OrganizationDomain{ + {IsPrimary: true, IsVerified: true, Domain: "old-org-name."}, + {IsPrimary: false, IsVerified: true, Domain: "old-org-name."}, + {IsPrimary: false, IsVerified: true, Domain: "old-org-name-2."}, + }, + }, nil) + + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetName("test org update")). + Times(1). + Return(int64(2), nil) + return repo + }, + inputID: "org-1", + inputName: "test org update", + expectedError: zerrors.ThrowInternal(domain.NewMultipleObjectsUpdatedError(1, 2), "DOM-QzITrx", "unexpected number of rows updated"), + expectedOldDomainName: gu.Ptr("old-org-name."), + expectedDomainVerified: gu.Ptr(true), + }, + { + testName: "when org update returns 1 row updated should return no error and set non-primary verified domain", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + LoadDomains(). + Times(1). + Return(repo) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "old org name", + InstanceID: "instance-1", + State: domain.OrgStateActive, + Domains: []*domain.OrganizationDomain{ + {IsPrimary: true, IsVerified: true, Domain: "old-org-name."}, + {IsPrimary: false, IsVerified: true, Domain: "old-org-name."}, + {IsPrimary: false, IsVerified: true, Domain: "old-org-name-2."}, + }, + }, nil) + + repo.EXPECT(). + Update(gomock.Any(), gomock.Any(), + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + repo.SetName("test org update")). + Times(1). + Return(int64(1), nil) + return repo + }, + inputID: "org-1", + inputName: "test org update", + + expectedOldDomainName: gu.Ptr("old-org-name."), + expectedDomainVerified: gu.Ptr(true), + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + ctx := authz.NewMockContext("instance-1", "", "") + ctrl := gomock.NewController(t) + cmd := domain.NewUpdateOrgCommand(tc.inputID, tc.inputName) + + opts := &domain.InvokeOpts{ + DB: new(noopdb.Pool), + } + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + if tc.queryExecutor != nil { + opts.DB = tc.queryExecutor(ctrl) + } + + // Test + err := cmd.Execute(ctx, opts) + + // Verify + assert.Equal(t, tc.expectedError, err) + assert.Equal(t, tc.expectedOldDomainName, cmd.OldDomainName) + assert.Equal(t, tc.expectedDomainVerified, cmd.IsOldDomainVerified) + }) + } +} + +func TestUpdateOrgCommand_Validate(t *testing.T) { + t.Parallel() + txInitErr := errors.New("tx init error") + getErr := errors.New("get error") + + tt := []struct { + testName string + queryExecutor func(ctrl *gomock.Controller) database.QueryExecutor + orgRepo func(ctrl *gomock.Controller) domain.OrganizationRepository + inputOrgID string + inputOrgName string + expectedError error + }{ + { + testName: "when no ID should return invalid argument error", + inputOrgID: "", + inputOrgName: "test-name", + expectedError: zerrors.ThrowInvalidArgument(nil, "DOM-lEMhVC", "invalid organization ID"), + }, + { + testName: "when no name shuld return invalid argument error", + inputOrgID: "test-id", + inputOrgName: "", + expectedError: zerrors.ThrowInvalidArgument(nil, "DOM-wfUntW", "invalid organization name"), + }, + { + testName: "when EnsureTx fails should return error", + queryExecutor: func(ctrl *gomock.Controller) database.QueryExecutor { + mockDB := dbmock.NewMockPool(ctrl) + mockDB.EXPECT(). + Begin(gomock.Any(), gomock.Any()). + Times(1). + Return(nil, txInitErr) + return mockDB + }, + inputOrgID: "test-id", + inputOrgName: "test-name", + expectedError: txInitErr, + }, + { + testName: "when retrieving org fails should return error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions( + database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(nil, getErr) + return repo + }, + inputOrgID: "org-1", + inputOrgName: "test org update", + expectedError: getErr, + }, + { + testName: "when org name is not changed should return name not changed error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "test org update", + }, nil) + return repo + }, + inputOrgID: "org-1", + inputOrgName: "test org update", + expectedError: zerrors.ThrowPreconditionFailed(nil, "DOM-nDzwIu", "Errors.Org.NotChanged"), + }, + { + testName: "when org name is changed should validate successfully and return no error", + orgRepo: func(ctrl *gomock.Controller) domain.OrganizationRepository { + repo := domainmock.NewOrgRepo(ctrl) + repo.EXPECT(). + Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(database.WithCondition( + database.And( + repo.IDCondition("org-1"), + repo.InstanceIDCondition("instance-1"), + ), + ))). + Times(1). + Return(&domain.Organization{ + ID: "org-1", + Name: "old org name", + }, nil) + return repo + }, + inputOrgID: "org-1", + inputOrgName: "test org update", + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + t.Parallel() + // Given + ctx := authz.NewMockContext("instance-1", "", "") + ctrl := gomock.NewController(t) + cmd := domain.NewUpdateOrgCommand(tc.inputOrgID, tc.inputOrgName) + + opts := &domain.InvokeOpts{ + DB: new(noopdb.Pool), + } + if tc.orgRepo != nil { + domain.WithOrganizationRepo(tc.orgRepo(ctrl))(opts) + } + if tc.queryExecutor != nil { + opts.DB = tc.queryExecutor(ctrl) + } + + err := cmd.Validate(ctx, opts) + assert.Equal(t, tc.expectedError, err) + }) + } +} + +func TestUpdateOrgCommand_Events(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + cmd *domain.UpdateOrgCommand + expectedCount int + }{ + { + name: "no old name, no events", + cmd: &domain.UpdateOrgCommand{ + ID: "org-1", + Name: "new-name", + OldDomainName: nil, + }, + expectedCount: 0, + }, + { + name: "old name equals new name, no events", + cmd: &domain.UpdateOrgCommand{ + ID: "org-1", + Name: "same-name", + OldDomainName: gu.Ptr("same-name"), + }, + expectedCount: 0, + }, + { + name: "old name different from new name, returns event", + cmd: &domain.UpdateOrgCommand{ + ID: "org-1", + Name: "new-name", + OldDomainName: gu.Ptr("old-name"), + }, + expectedCount: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + events, err := tt.cmd.Events(context.Background(), &domain.InvokeOpts{}) + require.Nil(t, err) + assert.Len(t, events, tt.expectedCount) + }) + } +} diff --git a/backend/v3/domain/organization.go b/backend/v3/domain/organization.go index 2bf92e448..cc99bebc9 100644 --- a/backend/v3/domain/organization.go +++ b/backend/v3/domain/organization.go @@ -10,9 +10,15 @@ import ( //go:generate enumer -type OrgState -transform lower -trimprefix OrgState -sql type OrgState uint8 +// Must be in the same order and quantity as zitadel/org/v2/org.proto const ( - OrgStateActive OrgState = iota + OrgStateUnspecified OrgState = iota + OrgStateActive OrgStateInactive + + // TODO(IAM-Marco): This should be removed in next versions of Zitadel I believe. We are hard deleting, + // so not sure when this state would be used. It is kept here just for compatibility with the gRPC model + OrgStateRemoved ) type Organization struct { @@ -67,6 +73,8 @@ type organizationChanges interface { SetState(state OrgState) database.Change } +//go:generate mockgen -typed -package domainmock -destination ./mock/org.mock.go . OrganizationRepository + // OrganizationRepository is the interface for the instance repository. type OrganizationRepository interface { organizationColumns @@ -98,3 +106,13 @@ type MemberRepository interface { SetMemberRoles(ctx context.Context, orgID, userID string, roles []string) error RemoveMember(ctx context.Context, orgID, userID string) error } + +func (o *Organization) PrimaryDomain() string { + for _, d := range o.Domains { + if d.IsPrimary { + return d.Domain + } + } + + return "" +} diff --git a/backend/v3/domain/organization_domain.go b/backend/v3/domain/organization_domain.go index 1e1b3877c..157e2c890 100644 --- a/backend/v3/domain/organization_domain.go +++ b/backend/v3/domain/organization_domain.go @@ -62,6 +62,8 @@ type organizationDomainChanges interface { SetValidationType(verificationType DomainValidationType) database.Change } +//go:generate mockgen -typed -package domainmock -destination ./mock/org_domain.mock.go . OrganizationDomainRepository + type OrganizationDomainRepository interface { organizationDomainColumns organizationDomainConditions diff --git a/backend/v3/domain/orgstate_enumer.go b/backend/v3/domain/orgstate_enumer.go index 69d4c053b..a20435874 100644 --- a/backend/v3/domain/orgstate_enumer.go +++ b/backend/v3/domain/orgstate_enumer.go @@ -8,11 +8,11 @@ import ( "strings" ) -const _OrgStateName = "activeinactive" +const _OrgStateName = "unspecifiedactiveinactiveremoved" -var _OrgStateIndex = [...]uint8{0, 6, 14} +var _OrgStateIndex = [...]uint8{0, 11, 17, 25, 32} -const _OrgStateLowerName = "activeinactive" +const _OrgStateLowerName = "unspecifiedactiveinactiveremoved" func (i OrgState) String() string { if i >= OrgState(len(_OrgStateIndex)-1) { @@ -25,22 +25,30 @@ func (i OrgState) String() string { // Re-run the stringer command to generate them again. func _OrgStateNoOp() { var x [1]struct{} - _ = x[OrgStateActive-(0)] - _ = x[OrgStateInactive-(1)] + _ = x[OrgStateUnspecified-(0)] + _ = x[OrgStateActive-(1)] + _ = x[OrgStateInactive-(2)] + _ = x[OrgStateRemoved-(3)] } -var _OrgStateValues = []OrgState{OrgStateActive, OrgStateInactive} +var _OrgStateValues = []OrgState{OrgStateUnspecified, OrgStateActive, OrgStateInactive, OrgStateRemoved} var _OrgStateNameToValueMap = map[string]OrgState{ - _OrgStateName[0:6]: OrgStateActive, - _OrgStateLowerName[0:6]: OrgStateActive, - _OrgStateName[6:14]: OrgStateInactive, - _OrgStateLowerName[6:14]: OrgStateInactive, + _OrgStateName[0:11]: OrgStateUnspecified, + _OrgStateLowerName[0:11]: OrgStateUnspecified, + _OrgStateName[11:17]: OrgStateActive, + _OrgStateLowerName[11:17]: OrgStateActive, + _OrgStateName[17:25]: OrgStateInactive, + _OrgStateLowerName[17:25]: OrgStateInactive, + _OrgStateName[25:32]: OrgStateRemoved, + _OrgStateLowerName[25:32]: OrgStateRemoved, } var _OrgStateNames = []string{ - _OrgStateName[0:6], - _OrgStateName[6:14], + _OrgStateName[0:11], + _OrgStateName[11:17], + _OrgStateName[17:25], + _OrgStateName[25:32], } // OrgStateString retrieves an enum value from the enum constants string name. diff --git a/backend/v3/domain/project.go b/backend/v3/domain/project.go index 885744b2b..f0d9de39d 100644 --- a/backend/v3/domain/project.go +++ b/backend/v3/domain/project.go @@ -91,6 +91,8 @@ type projectChanges interface { } // ProjectRepository manages projects and project roles. +// +//go:generate mockgen -typed -package domainmock -destination ./mock/project.mock.go . ProjectRepository type ProjectRepository interface { projectColumns projectConditions diff --git a/backend/v3/storage/database/change.go b/backend/v3/storage/database/change.go index 6581a2c4c..89d899364 100644 --- a/backend/v3/storage/database/change.go +++ b/backend/v3/storage/database/change.go @@ -1,10 +1,16 @@ package database -import "slices" +import ( + "reflect" + "slices" + + "go.uber.org/mock/gomock" +) // Change represents a change to a column in a database table. // Its written in the SET clause of an UPDATE statement. type Change interface { + gomock.Matcher // Write writes the change to the given statement builder. Write(builder *StatementBuilder) // IsOnColumn checks if the change is on the given column. @@ -16,7 +22,26 @@ type change[V Value] struct { value V } -var _ Change = (*change[string])(nil) +// Matches implements [gomock.Matcher]. +func (c *change[V]) Matches(x any) bool { + toMatch, ok := x.(*change[V]) + if !ok { + return false + } + colMatch := c.column.Equals(toMatch.column) + valueMatch := reflect.DeepEqual(c.value, toMatch.value) + return colMatch && valueMatch +} + +// String implements [gomock.Matcher]. +func (c *change[V]) String() string { + return "database.change" +} + +var ( + _ Change = (*change[string])(nil) + _ gomock.Matcher = (*change[string])(nil) +) // NewChange creates a new Change for the given column and value. // If you want to set a column to NULL, use [NewChangePtr]. @@ -71,4 +96,26 @@ func (m Changes) Write(builder *StatementBuilder) { } } +// Matches implements [gomock.Matcher]. +func (c Changes) Matches(x any) bool { + toMatch, ok := x.(*Changes) + if !ok { + return false + } + if len(c) != len(*toMatch) { + return false + } + for i := range c { + if !c[i].Matches((*toMatch)[i]) { + return false + } + } + return true +} + +// String implements [gomock.Matcher]. +func (c Changes) String() string { + return "database.Changes" +} + var _ Change = Changes(nil) diff --git a/backend/v3/storage/database/column.go b/backend/v3/storage/database/column.go index f1316048b..a2a510680 100644 --- a/backend/v3/storage/database/column.go +++ b/backend/v3/storage/database/column.go @@ -1,7 +1,25 @@ package database +import "go.uber.org/mock/gomock" + type Columns []Column +// Matches implements [Column]. +func (c Columns) Matches(x any) bool { + for _, col := range c { + if !col.Matches(x) { + return false + } + } + + return true +} + +// String implements [Column]. +func (c Columns) String() string { + return "database.Columns" +} + // WriteQualified implements [Column]. // Columns are separated by ", ". func (c Columns) WriteQualified(builder *StatementBuilder) { @@ -45,6 +63,7 @@ var _ Column = (Columns)(nil) // Column represents a column in a database table. type Column interface { + gomock.Matcher // WriteQualified writes the column with the table name as prefix. WriteQualified(builder *StatementBuilder) // WriteUnqualified writes the column without the table name as prefix. @@ -58,6 +77,20 @@ type column struct { name string } +// Matches implements [Column]. +func (c column) Matches(x any) bool { + toMatch, ok := x.(*column) + if !ok { + return false + } + return c.table == toMatch.table && c.name == toMatch.name +} + +// String implements [Column]. +func (c column) String() string { + return "database.column" +} + func NewColumn(table, name string) Column { return &column{table: table, name: name} } @@ -102,6 +135,26 @@ type functionColumn struct { col Column } +// Matches implements [Column]. +func (c *functionColumn) Matches(x any) bool { + toMatch, ok := x.(*functionColumn) + if !ok || toMatch.fn != c.fn { + return false + } + if toMatch.col == nil { + return c.col == nil + } + if c.col == nil { + return false + } + return toMatch.col.Matches(c.col) +} + +// String implements [Column]. +func (c *functionColumn) String() string { + return "database.functionColumn" +} + type function string const ( diff --git a/backend/v3/storage/database/condition.go b/backend/v3/storage/database/condition.go index 6bc1124f1..4658a258e 100644 --- a/backend/v3/storage/database/condition.go +++ b/backend/v3/storage/database/condition.go @@ -1,11 +1,14 @@ package database +import "go.uber.org/mock/gomock" + // Condition represents a SQL condition. // Its written after the WHERE keyword in a SQL statement. type Condition interface { + gomock.Matcher Write(builder *StatementBuilder) // IsRestrictingColumn is used to check if the condition filters for a specific column. - // It acts as a save guard database operations that should be specific on the given column. + // It acts as a safeguard database operations that should be specific on the given column. IsRestrictingColumn(col Column) bool } @@ -13,6 +16,28 @@ type and struct { conditions []Condition } +// Matches implements [Condition]. +func (a *and) Matches(x any) bool { + toMatch, ok := x.(*and) + if !ok { + return false + } + if len(a.conditions) != len(toMatch.conditions) { + return false + } + for i, condition := range a.conditions { + if !condition.Matches(toMatch.conditions[i]) { + return false + } + } + return true +} + +// String implements [Condition]. +func (a *and) String() string { + return "database.and" +} + // Write implements [Condition]. func (a and) Write(builder *StatementBuilder) { if len(a.conditions) > 1 { @@ -48,6 +73,28 @@ type or struct { conditions []Condition } +// Matches implements [Condition]. +func (o *or) Matches(x any) bool { + toMatch, ok := x.(*or) + if !ok { + return false + } + if len(o.conditions) != len(toMatch.conditions) { + return false + } + for i, condition := range o.conditions { + if !condition.Matches(toMatch.conditions[i]) { + return false + } + } + return true +} + +// String implements [Condition]. +func (o *or) String() string { + return "database.or" +} + // Write implements [Condition]. func (o or) Write(builder *StatementBuilder) { if len(o.conditions) > 1 { @@ -84,6 +131,20 @@ type isNull struct { column Column } +// Matches implements [Condition]. +func (i *isNull) Matches(x any) bool { + toMatch, ok := x.(*isNull) + if !ok { + return false + } + return i.column.Matches(toMatch.column) +} + +// String implements [Condition]. +func (i *isNull) String() string { + return "database.isNull" +} + // Write implements [Condition]. func (i isNull) Write(builder *StatementBuilder) { i.column.WriteQualified(builder) @@ -107,6 +168,20 @@ type isNotNull struct { column Column } +// Matches implements [Condition]. +func (i *isNotNull) Matches(x any) bool { + toMatch, ok := x.(*isNotNull) + if !ok { + return false + } + return i.column.Matches(toMatch.column) +} + +// String implements [Condition]. +func (i *isNotNull) String() string { + return "database.isNotNull" +} + // Write implements [Condition]. func (i isNotNull) Write(builder *StatementBuilder) { i.column.WriteQualified(builder) @@ -131,9 +206,32 @@ type valueCondition struct { col Column } +// Matches implements [Condition]. +func (c valueCondition) Matches(x any) bool { + toMatch, ok := x.(valueCondition) + if !ok { + return false + } + if !c.col.Matches(toMatch.col) { + return false + } + var expectedStatement, inputStatement StatementBuilder + c.write(&expectedStatement) + toMatch.write(&inputStatement) + return expectedStatement.String() == inputStatement.String() +} + +// String implements [Condition]. +func (c valueCondition) String() string { + return "database.valueCondition" +} + // NewTextCondition creates a condition that compares a text column with a value. -// If you want to use ignore case operations, consider using [NewTextIgnoreCaseCondition]. +// if `op.IsIgnoreCaseOperation()` is true the response is created using [NewTextIgnoreCaseCondition] func NewTextCondition[T Text](col Column, op TextOperation, value T) Condition { + if op.IsIgnoreCaseOperation() { + return NewTextIgnoreCaseCondition(col, op.Value(), value) + } return valueCondition{ col: col, write: func(builder *StatementBuilder) { @@ -207,12 +305,23 @@ func (i valueCondition) IsRestrictingColumn(col Column) bool { var _ Condition = (*valueCondition)(nil) // existsCondition is a helper to write an EXISTS (SELECT 1 FROM