Files
zitadel/backend/v3/storage/database/repository/project_role.go
T
SilvanandGitHub 07dbb48cc7 refactor: relational organization projection to use repository (#11621)
- Transitioned from using `handler.Statements` to a repository pattern
for managing organization data in migrations.
- Introduced a new method to set the updated timestamp for
organizations.
- Updated the projection logic to utilize the repository for creating,
updating, and deleting organization records.
2026-03-05 14:55:42 +01:00

222 lines
6.9 KiB
Go

package repository
import (
"context"
"time"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
)
// -------------------------------------------------------------
// repository
// -------------------------------------------------------------
type projectRole struct{}
func (projectRole) qualifiedTableName() string {
return "zitadel.project_roles"
}
func (p projectRole) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.ProjectRole, error) {
builder, err := p.prepareQuery(opts)
if err != nil {
return nil, err
}
return getOne[domain.ProjectRole](ctx, client, builder)
}
func (p projectRole) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.ProjectRole, error) {
builder, err := p.prepareQuery(opts)
if err != nil {
return nil, err
}
return getMany[domain.ProjectRole](ctx, client, builder)
}
func (p projectRole) Create(ctx context.Context, client database.QueryExecutor, role *domain.ProjectRole) error {
var (
builder database.StatementBuilder
createdAt, updatedAt any = database.DefaultInstruction, database.DefaultInstruction
)
if !role.CreatedAt.IsZero() {
createdAt = role.CreatedAt
}
if !role.UpdatedAt.IsZero() {
updatedAt = role.UpdatedAt
}
builder.WriteString("INSERT INTO ")
builder.WriteString(p.qualifiedTableName())
builder.WriteString(` (instance_id, organization_id, project_id, key, display_name, role_group, created_at, updated_at) VALUES (`)
builder.WriteArgs(
role.InstanceID,
role.OrganizationID,
role.ProjectID,
role.Key,
role.DisplayName,
role.RoleGroup,
createdAt,
updatedAt,
)
builder.WriteString(`) RETURNING created_at, updated_at`)
return client.QueryRow(ctx, builder.String(), builder.Args()...).
Scan(&role.CreatedAt, &role.UpdatedAt)
}
func (p projectRole) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) {
if len(changes) == 0 {
return 0, database.ErrNoChanges
}
if err := checkPKCondition(p, condition); err != nil {
return 0, err
}
if !database.Changes(changes).IsOnColumn(p.UpdatedAtColumn()) {
changes = append(changes, database.NewChange(p.UpdatedAtColumn(), database.NullInstruction))
}
builder := database.NewStatementBuilder(`UPDATE zitadel.project_roles SET `)
err := database.Changes(changes).Write(builder)
if err != nil {
return 0, err
}
writeCondition(builder, condition)
return client.Exec(ctx, builder.String(), builder.Args()...)
}
func (p projectRole) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) {
if err := checkPKCondition(p, condition); err != nil {
return 0, err
}
builder := database.NewStatementBuilder(`DELETE FROM zitadel.project_roles`)
writeCondition(builder, condition)
return client.Exec(ctx, builder.String(), builder.Args()...)
}
// -------------------------------------------------------------
// changes
// -------------------------------------------------------------
func (p projectRole) SetUpdatedAt(updatedAt time.Time) database.Change {
return database.NewChange(p.UpdatedAtColumn(), updatedAt)
}
func (p projectRole) SetDisplayName(displayName string) database.Change {
return database.NewChange(p.DisplayNameColumn(), displayName)
}
func (p projectRole) SetRoleGroup(roleGroup string) database.Change {
return database.NewChange(p.RoleGroupColumn(), roleGroup)
}
// -------------------------------------------------------------
// conditions
// -------------------------------------------------------------
func (p projectRole) PrimaryKeyCondition(instanceID, projectID, key string) database.Condition {
return database.And(
p.InstanceIDCondition(instanceID),
p.ProjectIDCondition(projectID),
p.KeyCondition(key),
)
}
func (p projectRole) InstanceIDCondition(instanceID string) database.Condition {
return database.NewTextCondition(p.InstanceIDColumn(), database.TextOperationEqual, instanceID)
}
func (p projectRole) ProjectIDCondition(projectID string) database.Condition {
return database.NewTextCondition(p.ProjectIDColumn(), database.TextOperationEqual, projectID)
}
func (p projectRole) KeyCondition(key string) database.Condition {
return database.NewTextCondition(p.KeyColumn(), database.TextOperationEqual, key)
}
func (p projectRole) DisplayNameCondition(op database.TextOperation, displayName string) database.Condition {
return database.NewTextCondition(p.DisplayNameColumn(), op, displayName)
}
func (p projectRole) RoleGroupCondition(op database.TextOperation, roleGroup string) database.Condition {
return database.NewTextCondition(p.RoleGroupColumn(), op, roleGroup)
}
// -------------------------------------------------------------
// columns
// -------------------------------------------------------------
func (projectRole) unqualifiedTableName() string {
return "project_roles"
}
// PrimaryKeyColumns implements the [pkRepository] interface
func (p projectRole) PrimaryKeyColumns() []database.Column {
return []database.Column{
p.InstanceIDColumn(),
p.ProjectIDColumn(),
p.KeyColumn(),
}
}
func (p projectRole) InstanceIDColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "instance_id")
}
func (p projectRole) OrganizationIDColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "organization_id")
}
func (p projectRole) ProjectIDColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "project_id")
}
func (p projectRole) CreatedAtColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "created_at")
}
func (p projectRole) UpdatedAtColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "updated_at")
}
func (p projectRole) KeyColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "key")
}
func (p projectRole) DisplayNameColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "display_name")
}
func (p projectRole) RoleGroupColumn() database.Column {
return database.NewColumn(p.unqualifiedTableName(), "role_group")
}
// -------------------------------------------------------------
// helpers
// -------------------------------------------------------------
const queryProjectRoleStmt = `SELECT
project_roles.instance_id,
project_roles.organization_id,
project_roles.project_id,
project_roles.created_at,
project_roles.updated_at,
project_roles.key,
project_roles.display_name,
project_roles.role_group
FROM zitadel.project_roles`
func (p projectRole) prepareQuery(opts []database.QueryOption) (*database.StatementBuilder, error) {
options := new(database.QueryOpts)
for _, opt := range opts {
opt(options)
}
if err := checkRestrictingColumns(options.Condition, p.InstanceIDColumn(), p.ProjectIDColumn()); err != nil {
return nil, err
}
builder := database.NewStatementBuilder(queryProjectRoleStmt)
options.Write(builder)
return builder, nil
}