mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 15:49:35 +00:00
chore(db): refactoring instance+org tables to not use deleted_at (#10270)
This commit is contained in:
@@ -9,16 +9,15 @@ import (
|
||||
)
|
||||
|
||||
type Instance struct {
|
||||
ID string `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
DefaultOrgID string `json:"defaultOrgId,omitempty" db:"default_org_id"`
|
||||
IAMProjectID string `json:"iamProjectId,omitempty" db:"iam_project_id"`
|
||||
ConsoleClientID string `json:"consoleClientId,omitempty" db:"console_client_id"`
|
||||
ConsoleAppID string `json:"consoleAppId,omitempty" db:"console_app_id"`
|
||||
DefaultLanguage string `json:"defaultLanguage,omitempty" db:"default_language"`
|
||||
CreatedAt time.Time `json:"createdAt" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updatedAt" db:"updated_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt" db:"deleted_at"`
|
||||
ID string `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
DefaultOrgID string `json:"defaultOrgId,omitempty" db:"default_org_id"`
|
||||
IAMProjectID string `json:"iamProjectId,omitempty" db:"iam_project_id"`
|
||||
ConsoleClientID string `json:"consoleClientId,omitempty" db:"console_client_id"`
|
||||
ConsoleAppID string `json:"consoleAppId,omitempty" db:"console_app_id"`
|
||||
DefaultLanguage string `json:"defaultLanguage,omitempty" db:"default_language"`
|
||||
CreatedAt time.Time `json:"createdAt" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updatedAt" db:"updated_at"`
|
||||
}
|
||||
|
||||
type instanceCacheIndex uint8
|
||||
@@ -58,8 +57,6 @@ type instanceColumns interface {
|
||||
CreatedAtColumn() database.Column
|
||||
// UpdatedAtColumn returns the column for the updated at field.
|
||||
UpdatedAtColumn() database.Column
|
||||
// DeletedAtColumn returns the column for the deleted at field.
|
||||
DeletedAtColumn() database.Column
|
||||
}
|
||||
|
||||
// instanceConditions define all the conditions for the instance table.
|
||||
|
@@ -16,13 +16,12 @@ const (
|
||||
)
|
||||
|
||||
type Organization struct {
|
||||
ID string `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
InstanceID string `json:"instanceId,omitempty" db:"instance_id"`
|
||||
State string `json:"state,omitempty" db:"state"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
|
||||
ID string `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
InstanceID string `json:"instanceId,omitempty" db:"instance_id"`
|
||||
State string `json:"state,omitempty" db:"state"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
}
|
||||
|
||||
// OrgIdentifierCondition is used to help specify a single Organization,
|
||||
@@ -46,8 +45,6 @@ type organizationColumns interface {
|
||||
CreatedAtColumn() database.Column
|
||||
// UpdatedAtColumn returns the column for the updated at field.
|
||||
UpdatedAtColumn() database.Column
|
||||
// DeletedAtColumn returns the column for the deleted at field.
|
||||
DeletedAtColumn() database.Column
|
||||
}
|
||||
|
||||
// organizationConditions define all the conditions for the instance table.
|
||||
@@ -77,7 +74,7 @@ type OrganizationRepository interface {
|
||||
organizationChanges
|
||||
|
||||
Get(ctx context.Context, id OrgIdentifierCondition, instance_id string, opts ...database.Condition) (*Organization, error)
|
||||
List(ctx context.Context, opts ...database.Condition) ([]*Organization, error)
|
||||
List(ctx context.Context, conditions ...database.Condition) ([]*Organization, error)
|
||||
|
||||
Create(ctx context.Context, instance *Organization) error
|
||||
Update(ctx context.Context, id OrgIdentifierCondition, instance_id string, changes ...database.Change) (int64, error)
|
||||
|
@@ -7,8 +7,7 @@ CREATE TABLE IF NOT EXISTS zitadel.instances(
|
||||
console_app_id TEXT, -- NOT NULL,
|
||||
default_language TEXT, -- NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
||||
deleted_at TIMESTAMPTZ DEFAULT NULL
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION zitadel.set_updated_at()
|
||||
|
@@ -10,21 +10,12 @@ CREATE TABLE zitadel.organizations(
|
||||
state zitadel.organization_state NOT NULL,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
|
||||
deleted_at TIMESTAMPTZ DEFAULT NULL,
|
||||
|
||||
PRIMARY KEY (instance_id, id)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX org_unique_instance_id_name_idx
|
||||
ON zitadel.organizations (instance_id, name)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- users are able to set the id for organizations
|
||||
CREATE INDEX org_id_not_deleted_idx ON zitadel.organizations (id)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE INDEX org_name_not_deleted_idx ON zitadel.organizations (name)
|
||||
WHERE deleted_at IS NULL;
|
||||
ON zitadel.organizations (instance_id, name);
|
||||
|
||||
CREATE TRIGGER trigger_set_updated_at
|
||||
BEFORE UPDATE ON zitadel.organizations
|
||||
|
@@ -54,7 +54,6 @@ func TestServer_TestInstanceReduces(t *testing.T) {
|
||||
assert.WithinRange(t, instance.CreatedAt, beforeCreate, afterCreate)
|
||||
// event instance.added
|
||||
assert.WithinRange(t, instance.UpdatedAt, beforeCreate, afterCreate)
|
||||
assert.Nil(t, instance.DeletedAt)
|
||||
}, retryDuration, tick)
|
||||
})
|
||||
|
||||
@@ -132,7 +131,7 @@ func TestServer_TestInstanceReduces(t *testing.T) {
|
||||
)
|
||||
// event instance.removed
|
||||
assert.Nil(t, instance)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, repository.ErrResourceDoesNotExist, err)
|
||||
}, retryDuration, tick)
|
||||
})
|
||||
}
|
||||
|
@@ -46,7 +46,6 @@ func TestServer_TestOrganizationReduces(t *testing.T) {
|
||||
assert.Equal(t, domain.OrgStateActive.String(), organization.State)
|
||||
assert.WithinRange(t, organization.CreatedAt, beforeCreate, afterCreate)
|
||||
assert.WithinRange(t, organization.UpdatedAt, beforeCreate, afterCreate)
|
||||
assert.Nil(t, organization.DeletedAt)
|
||||
}, retryDuration, tick)
|
||||
})
|
||||
|
||||
@@ -209,7 +208,7 @@ func TestServer_TestOrganizationReduces(t *testing.T) {
|
||||
orgRepo.NameCondition(orgName),
|
||||
instanceID,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, repository.ErrResourceDoesNotExist, err)
|
||||
|
||||
// event org.remove
|
||||
assert.Nil(t, organization)
|
||||
|
@@ -3,7 +3,6 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
|
||||
@@ -29,7 +28,7 @@ func InstanceRepository(client database.QueryExecutor) domain.InstanceRepository
|
||||
// repository
|
||||
// -------------------------------------------------------------
|
||||
|
||||
const queryInstanceStmt = `SELECT id, name, default_org_id, iam_project_id, console_client_id, console_app_id, default_language, created_at, updated_at, deleted_at` +
|
||||
const queryInstanceStmt = `SELECT id, name, default_org_id, iam_project_id, console_client_id, console_app_id, default_language, created_at, updated_at` +
|
||||
` FROM zitadel.instances`
|
||||
|
||||
// Get implements [domain.InstanceRepository].
|
||||
@@ -39,23 +38,20 @@ func (i *instance) Get(ctx context.Context, id string) (*domain.Instance, error)
|
||||
builder.WriteString(queryInstanceStmt)
|
||||
|
||||
idCondition := i.IDCondition(id)
|
||||
// return only non deleted instances
|
||||
conditions := []database.Condition{idCondition, database.IsNull(i.DeletedAtColumn())}
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
writeCondition(&builder, idCondition)
|
||||
|
||||
return scanInstance(ctx, i.client, &builder)
|
||||
}
|
||||
|
||||
// List implements [domain.InstanceRepository].
|
||||
func (i *instance) List(ctx context.Context, opts ...database.Condition) ([]*domain.Instance, error) {
|
||||
func (i *instance) List(ctx context.Context, conditions ...database.Condition) ([]*domain.Instance, error) {
|
||||
var builder database.StatementBuilder
|
||||
|
||||
builder.WriteString(queryInstanceStmt)
|
||||
|
||||
// return only non deleted instances
|
||||
opts = append(opts, database.IsNull(i.DeletedAtColumn()))
|
||||
notDeletedCondition := database.And(opts...)
|
||||
writeCondition(&builder, notDeletedCondition)
|
||||
if conditions != nil {
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
}
|
||||
|
||||
return scanInstances(ctx, i.client, &builder)
|
||||
}
|
||||
@@ -107,9 +103,7 @@ func (i instance) Update(ctx context.Context, id string, changes ...database.Cha
|
||||
database.Changes(changes).Write(&builder)
|
||||
|
||||
idCondition := i.IDCondition(id)
|
||||
// don't update deleted instances
|
||||
conditions := []database.Condition{idCondition, database.IsNull(i.DeletedAtColumn())}
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
writeCondition(&builder, idCondition)
|
||||
|
||||
stmt := builder.String()
|
||||
|
||||
@@ -121,13 +115,10 @@ func (i instance) Update(ctx context.Context, id string, changes ...database.Cha
|
||||
func (i instance) Delete(ctx context.Context, id string) (int64, error) {
|
||||
var builder database.StatementBuilder
|
||||
|
||||
builder.WriteString(`UPDATE zitadel.instances SET deleted_at = $1`)
|
||||
builder.AppendArgs(time.Now())
|
||||
builder.WriteString(`DELETE FROM zitadel.instances`)
|
||||
|
||||
// don't delete already deleted instance
|
||||
idCondition := i.IDCondition(id)
|
||||
conditions := []database.Condition{idCondition, database.IsNull(i.DeletedAtColumn())}
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
writeCondition(&builder, idCondition)
|
||||
|
||||
return i.client.Exec(ctx, builder.String(), builder.Args()...)
|
||||
}
|
||||
@@ -204,11 +195,6 @@ func (instance) UpdatedAtColumn() database.Column {
|
||||
return database.NewColumn("updated_at")
|
||||
}
|
||||
|
||||
// DeletedAtColumn implements [domain.instanceColumns].
|
||||
func (instance) DeletedAtColumn() database.Column {
|
||||
return database.NewColumn("deleted_at")
|
||||
}
|
||||
|
||||
func scanInstance(ctx context.Context, querier database.Querier, builder *database.StatementBuilder) (*domain.Instance, error) {
|
||||
rows, err := querier.Query(ctx, builder.String(), builder.Args()...)
|
||||
if err != nil {
|
||||
|
@@ -185,7 +185,6 @@ func TestCreateInstance(t *testing.T) {
|
||||
assert.Equal(t, tt.instance.DefaultLanguage, instance.DefaultLanguage)
|
||||
assert.WithinRange(t, instance.CreatedAt, beforeCreate, afterCreate)
|
||||
assert.WithinRange(t, instance.UpdatedAt, beforeCreate, afterCreate)
|
||||
assert.Nil(t, instance.DeletedAt)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -298,7 +297,6 @@ func TestUpdateInstance(t *testing.T) {
|
||||
|
||||
assert.Equal(t, newName, instance.Name)
|
||||
assert.WithinRange(t, instance.UpdatedAt, beforeUpdate, afterUpdate)
|
||||
assert.Nil(t, instance.DeletedAt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
|
||||
@@ -29,7 +28,7 @@ func OrganizationRepository(client database.QueryExecutor) domain.OrganizationRe
|
||||
}
|
||||
}
|
||||
|
||||
const queryOrganizationStmt = `SELECT id, name, instance_id, state, created_at, updated_at, deleted_at` +
|
||||
const queryOrganizationStmt = `SELECT id, name, instance_id, state, created_at, updated_at` +
|
||||
` FROM zitadel.organizations`
|
||||
|
||||
// Get implements [domain.OrganizationRepository].
|
||||
@@ -39,24 +38,22 @@ func (o *org) Get(ctx context.Context, id domain.OrgIdentifierCondition, instanc
|
||||
builder.WriteString(queryOrganizationStmt)
|
||||
|
||||
instanceIDCondition := o.InstanceIDCondition(instanceID)
|
||||
// don't update deleted organizations
|
||||
nonDeletedOrgs := database.IsNull(o.DeletedAtColumn())
|
||||
|
||||
conditions = append(conditions, id, instanceIDCondition, nonDeletedOrgs)
|
||||
conditions = append(conditions, id, instanceIDCondition)
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
|
||||
return scanOrganization(ctx, o.client, &builder)
|
||||
}
|
||||
|
||||
// List implements [domain.OrganizationRepository].
|
||||
func (o *org) List(ctx context.Context, opts ...database.Condition) ([]*domain.Organization, error) {
|
||||
func (o *org) List(ctx context.Context, conditions ...database.Condition) ([]*domain.Organization, error) {
|
||||
builder := database.StatementBuilder{}
|
||||
|
||||
builder.WriteString(queryOrganizationStmt)
|
||||
|
||||
// return only non deleted organizations
|
||||
opts = append(opts, database.IsNull(o.DeletedAtColumn()))
|
||||
writeCondition(&builder, database.And(opts...))
|
||||
if conditions != nil {
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
}
|
||||
|
||||
orderBy := database.OrderBy(o.CreatedAtColumn())
|
||||
orderBy.Write(&builder)
|
||||
@@ -122,10 +119,8 @@ func (o org) Update(ctx context.Context, id domain.OrgIdentifierCondition, insta
|
||||
builder.WriteString(`UPDATE zitadel.organizations SET `)
|
||||
|
||||
instanceIDCondition := o.InstanceIDCondition(instanceID)
|
||||
// don't update deleted organizations
|
||||
nonDeletedOrgs := database.IsNull(o.DeletedAtColumn())
|
||||
|
||||
conditions := []database.Condition{id, instanceIDCondition, nonDeletedOrgs}
|
||||
conditions := []database.Condition{id, instanceIDCondition}
|
||||
database.Changes(changes).Write(&builder)
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
|
||||
@@ -139,14 +134,11 @@ func (o org) Update(ctx context.Context, id domain.OrgIdentifierCondition, insta
|
||||
func (o org) Delete(ctx context.Context, id domain.OrgIdentifierCondition, instanceID string) (int64, error) {
|
||||
builder := database.StatementBuilder{}
|
||||
|
||||
builder.WriteString(`UPDATE zitadel.organizations SET deleted_at = $1`)
|
||||
builder.AppendArgs(time.Now())
|
||||
builder.WriteString(`DELETE FROM zitadel.organizations`)
|
||||
|
||||
instanceIDCondition := o.InstanceIDCondition(instanceID)
|
||||
// don't update deleted organizations
|
||||
nonDeletedOrgs := database.IsNull(o.DeletedAtColumn())
|
||||
|
||||
conditions := []database.Condition{id, instanceIDCondition, nonDeletedOrgs}
|
||||
conditions := []database.Condition{id, instanceIDCondition}
|
||||
writeCondition(&builder, database.And(conditions...))
|
||||
|
||||
return o.client.Exec(ctx, builder.String(), builder.Args()...)
|
||||
@@ -224,11 +216,6 @@ func (org) UpdatedAtColumn() database.Column {
|
||||
return database.NewColumn("updated_at")
|
||||
}
|
||||
|
||||
// DeletedAtColumn implements [domain.organizationColumns].
|
||||
func (org) DeletedAtColumn() database.Column {
|
||||
return database.NewColumn("deleted_at")
|
||||
}
|
||||
|
||||
func scanOrganization(ctx context.Context, querier database.Querier, builder *database.StatementBuilder) (*domain.Organization, error) {
|
||||
rows, err := querier.Query(ctx, builder.String(), builder.Args()...)
|
||||
if err != nil {
|
||||
|
@@ -247,7 +247,6 @@ func TestCreateOrganization(t *testing.T) {
|
||||
assert.Equal(t, tt.organization.State, organization.State)
|
||||
assert.WithinRange(t, organization.CreatedAt, beforeCreate, afterCreate)
|
||||
assert.WithinRange(t, organization.UpdatedAt, beforeCreate, afterCreate)
|
||||
assert.Nil(t, organization.DeletedAt)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -400,7 +399,6 @@ func TestUpdateOrganization(t *testing.T) {
|
||||
assert.Equal(t, createdOrg.Name, organization.Name)
|
||||
assert.Equal(t, createdOrg.State, organization.State)
|
||||
assert.WithinRange(t, organization.UpdatedAt, beforeUpdate, afterUpdate)
|
||||
assert.Nil(t, organization.DeletedAt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user