diff --git a/backend/v3/domain/organization.go b/backend/v3/domain/organization.go index a72b024da7..5eb377f852 100644 --- a/backend/v3/domain/organization.go +++ b/backend/v3/domain/organization.go @@ -125,8 +125,10 @@ func NewActivateOrganizationCommand(instanceID, orgID string) *ActivateOrganizat func (cmd *ActivateOrganizationCommand) Execute(ctx context.Context, opts *CommandOpts) (err error) { repo := orgRepo(opts.DB) _, err = repo.Update(ctx, - repo.IDCondition(cmd.OrgID), - cmd.InstanceID, + database.And( + repo.InstanceIDCondition(cmd.InstanceID), + repo.IDCondition(cmd.OrgID), + ), repo.SetState(OrgStateActive), ) return err @@ -160,8 +162,10 @@ func NewDeactivateOrganizationCommand(instanceID, orgID string) *DeactivateOrgan func (cmd *DeactivateOrganizationCommand) Execute(ctx context.Context, opts *CommandOpts) (err error) { repo := orgRepo(opts.DB) _, err = repo.Update(ctx, - repo.IDCondition(cmd.OrgID), - cmd.InstanceID, + database.And( + repo.InstanceIDCondition(cmd.InstanceID), + repo.IDCondition(cmd.OrgID), + ), repo.SetState(OrgStateInactive), ) return err @@ -192,8 +196,10 @@ func NewDeleteOrganizationCommand(instanceID, orgID string) *DeleteOrganizationC func (cmd *DeleteOrganizationCommand) Execute(ctx context.Context, opts *CommandOpts) (err error) { repo := orgRepo(opts.DB) _, err = repo.Delete(ctx, - repo.IDCondition(cmd.OrgID), - cmd.InstanceID, + database.And( + repo.InstanceIDCondition(cmd.InstanceID), + repo.IDCondition(cmd.OrgID), + ), ) return err } @@ -238,8 +244,10 @@ func (cmd *UpdateOrganizationCommand) Execute(ctx context.Context, opts *Command } _, err = cmd.repo.Update(ctx, - cmd.repo.IDCondition(cmd.OrgID), - cmd.InstanceID, + database.And( + cmd.repo.InstanceIDCondition(cmd.InstanceID), + cmd.repo.IDCondition(cmd.OrgID), + ), cmd.changes..., ) return err diff --git a/backend/v3/domain/organization_repository.go b/backend/v3/domain/organization_repository.go index ce73350876..3343bc4876 100644 --- a/backend/v3/domain/organization_repository.go +++ b/backend/v3/domain/organization_repository.go @@ -16,8 +16,8 @@ type OrganizationRepository interface { List(ctx context.Context, opts ...database.QueryOption) ([]*Organization, error) Create(ctx context.Context, instance *Organization) error - Update(ctx context.Context, id OrgIdentifierCondition, instance_id string, changes ...database.Change) (int64, error) - Delete(ctx context.Context, id OrgIdentifierCondition, instance_id string) (int64, error) + Update(ctx context.Context, condition database.Condition, changes ...database.Change) (int64, error) + Delete(ctx context.Context, condition database.Condition) (int64, error) // Domains returns the domain sub repository for the organization. // If shouldLoad is true, the domains will be loaded from the database and written to the [Organization].Domains field. @@ -25,13 +25,6 @@ type OrganizationRepository interface { Domains(shouldLoad bool) OrganizationDomainRepository } -// OrgIdentifierCondition is used to help specify a single Organization, -// it will either be used as the organization ID or organization name, -// as organizations can be identified either using (instanceID + ID) OR (instanceID + name) -type OrgIdentifierCondition interface { - database.Condition -} - // organizationColumns define all the columns of the instance table. type organizationColumns interface { // IDColumn returns the column for the id field. @@ -57,9 +50,9 @@ type organizationColumns interface { // organizationConditions define all the conditions for the instance table. type organizationConditions interface { // IDCondition returns an equal filter on the id field. - IDCondition(id string) OrgIdentifierCondition + IDCondition(id string) database.Condition // NameCondition returns a filter on the name field. - NameCondition(name string) OrgIdentifierCondition + NameCondition(op database.TextOperation, name string) database.Condition // InstanceIDCondition returns a filter on the instance id field. InstanceIDCondition(instanceID string) database.Condition // StateCondition returns a filter on the name field. diff --git a/backend/v3/storage/database/repository/org.go b/backend/v3/storage/database/repository/org.go index cd9071c1ab..c8b981e0c0 100644 --- a/backend/v3/storage/database/repository/org.go +++ b/backend/v3/storage/database/repository/org.go @@ -103,35 +103,24 @@ func (o *org) Create(ctx context.Context, organization *domain.Organization) err } // Update implements [domain.OrganizationRepository]. -func (o *org) Update(ctx context.Context, id domain.OrgIdentifierCondition, instanceID string, changes ...database.Change) (int64, error) { +func (o *org) Update(ctx context.Context, condition database.Condition, changes ...database.Change) (int64, error) { if len(changes) == 0 { return 0, database.ErrNoChanges } builder := database.StatementBuilder{} builder.WriteString(`UPDATE zitadel.organizations SET `) - - instanceIDCondition := o.InstanceIDCondition(instanceID) - - conditions := []database.Condition{id, instanceIDCondition} database.Changes(changes).Write(&builder) - writeCondition(&builder, database.And(conditions...)) + writeCondition(&builder, condition) - stmt := builder.String() - - rowsAffected, err := o.client.Exec(ctx, stmt, builder.Args()...) + rowsAffected, err := o.client.Exec(ctx, builder.String(), builder.Args()...) return rowsAffected, err } // Delete implements [domain.OrganizationRepository]. -func (o *org) Delete(ctx context.Context, id domain.OrgIdentifierCondition, instanceID string) (int64, error) { +func (o *org) Delete(ctx context.Context, condition database.Condition) (int64, error) { builder := database.StatementBuilder{} - builder.WriteString(`DELETE FROM zitadel.organizations`) - - instanceIDCondition := o.InstanceIDCondition(instanceID) - - conditions := []database.Condition{id, instanceIDCondition} - writeCondition(&builder, database.And(conditions...)) + writeCondition(&builder, condition) return o.client.Exec(ctx, builder.String(), builder.Args()...) } @@ -155,13 +144,13 @@ func (o org) SetState(state domain.OrgState) database.Change { // ------------------------------------------------------------- // IDCondition implements [domain.organizationConditions]. -func (o org) IDCondition(id string) domain.OrgIdentifierCondition { +func (o org) IDCondition(id string) database.Condition { return database.NewTextCondition(o.IDColumn(true), database.TextOperationEqual, id) } // NameCondition implements [domain.organizationConditions]. -func (o org) NameCondition(name string) domain.OrgIdentifierCondition { - return database.NewTextCondition(o.NameColumn(true), database.TextOperationEqual, name) +func (o org) NameCondition(op database.TextOperation, name string) database.Condition { + return database.NewTextCondition(o.NameColumn(true), op, name) } // InstanceIDCondition implements [domain.organizationConditions]. diff --git a/backend/v3/storage/database/repository/org_test.go b/backend/v3/storage/database/repository/org_test.go index e8e2183715..92d235c204 100644 --- a/backend/v3/storage/database/repository/org_test.go +++ b/backend/v3/storage/database/repository/org_test.go @@ -320,8 +320,10 @@ func TestUpdateOrganization(t *testing.T) { // delete instance _, err = organizationRepo.Delete(ctx, - organizationRepo.IDCondition(org.ID), - org.InstanceID, + database.And( + organizationRepo.IDCondition(org.ID), + organizationRepo.InstanceIDCondition(org.InstanceID), + ), ) require.NoError(t, err) @@ -378,8 +380,10 @@ func TestUpdateOrganization(t *testing.T) { // update org beforeUpdate := time.Now() rowsAffected, err := organizationRepo.Update(ctx, - organizationRepo.IDCondition(createdOrg.ID), - createdOrg.InstanceID, + database.And( + organizationRepo.IDCondition(createdOrg.ID), + organizationRepo.InstanceIDCondition(createdOrg.InstanceID), + ), tt.update..., ) afterUpdate := time.Now() @@ -441,10 +445,10 @@ func TestGetOrganization(t *testing.T) { require.NoError(t, err) type test struct { - name string - testFunc func(ctx context.Context, t *testing.T) *domain.Organization - orgIdentifierCondition domain.OrgIdentifierCondition - err error + name string + testFunc func(ctx context.Context, t *testing.T) *domain.Organization + condition database.Condition + err error } tests := []test{ @@ -468,7 +472,7 @@ func TestGetOrganization(t *testing.T) { return &org }, - orgIdentifierCondition: orgRepo.IDCondition(organizationId), + condition: orgRepo.IDCondition(organizationId), } }(), func() test { @@ -491,7 +495,7 @@ func TestGetOrganization(t *testing.T) { return &org }, - orgIdentifierCondition: orgRepo.NameCondition(organizationName), + condition: orgRepo.NameCondition(database.TextOperationEqual, organizationName), } }(), { @@ -503,8 +507,8 @@ func TestGetOrganization(t *testing.T) { } return &org }, - orgIdentifierCondition: orgRepo.NameCondition("non-existent-instance-name"), - err: new(database.NoRowFoundError), + condition: orgRepo.NameCondition(database.TextOperationEqual, "non-existent-instance-name"), + err: new(database.NoRowFoundError), }, } for _, tt := range tests { @@ -521,7 +525,7 @@ func TestGetOrganization(t *testing.T) { returnedOrg, err := orgRepo.Get(ctx, database.WithCondition( database.And( - tt.orgIdentifierCondition, + tt.condition, orgRepo.InstanceIDCondition(org.InstanceID), ), ), @@ -821,10 +825,10 @@ func TestDeleteOrganization(t *testing.T) { require.NoError(t, err) type test struct { - name string - testFunc func(ctx context.Context, t *testing.T) - orgIdentifierCondition domain.OrgIdentifierCondition - noOfDeletedRows int64 + name string + testFunc func(ctx context.Context, t *testing.T) + condition database.Condition + noOfDeletedRows int64 } tests := []test{ func() test { @@ -851,8 +855,8 @@ func TestDeleteOrganization(t *testing.T) { organizations[i] = &org } }, - orgIdentifierCondition: organizationRepo.IDCondition(organizationId), - noOfDeletedRows: noOfOrganizations, + condition: organizationRepo.IDCondition(organizationId), + noOfDeletedRows: noOfOrganizations, } }(), func() test { @@ -879,16 +883,16 @@ func TestDeleteOrganization(t *testing.T) { organizations[i] = &org } }, - orgIdentifierCondition: organizationRepo.NameCondition(organizationName), - noOfDeletedRows: noOfOrganizations, + condition: organizationRepo.NameCondition(database.TextOperationEqual, organizationName), + noOfDeletedRows: noOfOrganizations, } }(), func() test { organizationRepo := repository.OrganizationRepository(pool) - non_existent_organization_name := gofakeit.Name() + nonExistentOrgName := gofakeit.Name() return test{ - name: "delete non existent organization", - orgIdentifierCondition: organizationRepo.NameCondition(non_existent_organization_name), + name: "delete non existent organization", + condition: organizationRepo.NameCondition(database.TextOperationEqual, nonExistentOrgName), } }(), func() test { @@ -917,13 +921,15 @@ func TestDeleteOrganization(t *testing.T) { // delete organization affectedRows, err := organizationRepo.Delete(ctx, - organizationRepo.NameCondition(organizationName), - organizations[0].InstanceID, + database.And( + organizationRepo.NameCondition(database.TextOperationEqual, organizationName), + organizationRepo.InstanceIDCondition(organizations[0].InstanceID), + ), ) assert.Equal(t, int64(1), affectedRows) require.NoError(t, err) }, - orgIdentifierCondition: organizationRepo.NameCondition(organizationName), + condition: organizationRepo.NameCondition(database.TextOperationEqual, organizationName), // this test should return 0 affected rows as the org was already deleted noOfDeletedRows: 0, } @@ -940,8 +946,7 @@ func TestDeleteOrganization(t *testing.T) { // delete organization noOfDeletedRows, err := organizationRepo.Delete(ctx, - tt.orgIdentifierCondition, - instanceId, + tt.condition, ) require.NoError(t, err) assert.Equal(t, noOfDeletedRows, tt.noOfDeletedRows) @@ -950,7 +955,7 @@ func TestDeleteOrganization(t *testing.T) { organization, err := organizationRepo.Get(ctx, database.WithCondition( database.And( - tt.orgIdentifierCondition, + tt.condition, organizationRepo.InstanceIDCondition(instanceId), ), ),