mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-20 22:44:25 +00:00
- 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.
311 lines
9.6 KiB
Go
311 lines
9.6 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/zitadel/zitadel/backend/v3/domain"
|
|
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
|
)
|
|
|
|
// -------------------------------------------------------------
|
|
// repository
|
|
// -------------------------------------------------------------
|
|
|
|
type project struct{}
|
|
|
|
// ProjectRepository manages projects and project roles.
|
|
func ProjectRepository() domain.ProjectRepository {
|
|
return project{}
|
|
}
|
|
|
|
func (project) Role() domain.ProjectRoleRepository {
|
|
return projectRole{}
|
|
}
|
|
|
|
func (p project) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.Project, error) {
|
|
builder, err := p.prepareGetQuery(opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return getOne[domain.Project](ctx, client, builder)
|
|
}
|
|
|
|
func (p project) List(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) ([]*domain.Project, error) {
|
|
builder, err := p.prepareListQuery(opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return getMany[domain.Project](ctx, client, builder)
|
|
}
|
|
|
|
func (p project) Create(ctx context.Context, client database.QueryExecutor, project *domain.Project) error {
|
|
var (
|
|
builder database.StatementBuilder
|
|
createdAt, updatedAt any = database.DefaultInstruction, database.DefaultInstruction
|
|
)
|
|
if !project.CreatedAt.IsZero() {
|
|
createdAt = project.CreatedAt
|
|
}
|
|
if !project.UpdatedAt.IsZero() {
|
|
updatedAt = project.UpdatedAt
|
|
}
|
|
|
|
builder.WriteString("INSERT INTO ")
|
|
builder.WriteString(p.qualifiedTableName())
|
|
builder.WriteString("(instance_id, organization_id, id, name, state, should_assert_role, is_authorization_required, is_project_access_required, used_labeling_setting_owner, created_at, updated_at) VALUES (")
|
|
builder.WriteArgs(
|
|
project.InstanceID,
|
|
project.OrganizationID,
|
|
project.ID,
|
|
project.Name,
|
|
project.State,
|
|
project.ShouldAssertRole,
|
|
project.IsAuthorizationRequired,
|
|
project.IsProjectAccessRequired,
|
|
project.UsedLabelingSettingOwner,
|
|
createdAt,
|
|
updatedAt,
|
|
)
|
|
builder.WriteString(`) RETURNING created_at, updated_at`)
|
|
|
|
return client.QueryRow(ctx, builder.String(), builder.Args()...).
|
|
Scan(&project.CreatedAt, &project.UpdatedAt)
|
|
}
|
|
|
|
func (p project) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) {
|
|
return updateOne(ctx, client, p, condition, changes...)
|
|
}
|
|
|
|
func (p project) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) {
|
|
return deleteOne(ctx, client, p, condition)
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// changes
|
|
// -------------------------------------------------------------
|
|
|
|
func (p project) SetUpdatedAt(updatedAt time.Time) database.Change {
|
|
return database.NewChange(p.UpdatedAtColumn(), updatedAt)
|
|
}
|
|
|
|
func (p project) SetName(name string) database.Change {
|
|
return database.NewChange(p.NameColumn(), name)
|
|
}
|
|
|
|
func (p project) SetState(state domain.ProjectState) database.Change {
|
|
return database.NewChange(p.StateColumn(), state)
|
|
}
|
|
|
|
func (p project) SetShouldAssertRole(shouldAssertRole bool) database.Change {
|
|
return database.NewChange(p.ShouldAssertRoleColumn(), shouldAssertRole)
|
|
}
|
|
|
|
func (p project) SetIsAuthorizationRequired(isAuthorizationRequired bool) database.Change {
|
|
return database.NewChange(p.IsAuthorizationRequiredColumn(), isAuthorizationRequired)
|
|
}
|
|
|
|
func (p project) SetIsProjectAccessRequired(isProjectAccessRequired bool) database.Change {
|
|
return database.NewChange(p.IsProjectAccessRequiredColumn(), isProjectAccessRequired)
|
|
}
|
|
|
|
func (p project) SetUsedLabelingSettingOwner(usedLabelingSettingOwner int16) database.Change {
|
|
return database.NewChange(p.UsedLabelingSettingOwnerColumn(), usedLabelingSettingOwner)
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// conditions
|
|
// -------------------------------------------------------------
|
|
|
|
func (p project) PrimaryKeyCondition(instanceID, projectID string) database.Condition {
|
|
return database.And(
|
|
p.InstanceIDCondition(instanceID),
|
|
p.IDCondition(projectID),
|
|
)
|
|
}
|
|
|
|
func (p project) InstanceIDCondition(instanceID string) database.Condition {
|
|
return database.NewTextCondition(p.InstanceIDColumn(), database.TextOperationEqual, instanceID)
|
|
}
|
|
|
|
func (p project) OrganizationIDCondition(organizationID string) database.Condition {
|
|
return database.NewTextCondition(p.OrganizationIDColumn(), database.TextOperationEqual, organizationID)
|
|
}
|
|
|
|
func (p project) GrantedOrganizationIDCondition(organizationID string) database.Condition {
|
|
return database.NewTextCondition(p.GrantedOrganizationIDColumn(), database.TextOperationEqual, organizationID)
|
|
}
|
|
|
|
func (p project) IDCondition(projectID string) database.Condition {
|
|
return database.NewTextCondition(p.IDColumn(), database.TextOperationEqual, projectID)
|
|
}
|
|
|
|
func (p project) NameCondition(op database.TextOperation, name string) database.Condition {
|
|
return database.NewTextCondition(p.NameColumn(), op, name)
|
|
}
|
|
|
|
func (p project) StateCondition(state domain.ProjectState) database.Condition {
|
|
return database.NewTextCondition(p.StateColumn(), database.TextOperationEqual, state.String())
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// columns
|
|
// -------------------------------------------------------------
|
|
|
|
func (p project) qualifiedTableName() string {
|
|
return "zitadel.projects"
|
|
}
|
|
|
|
func (project) unqualifiedTableName() string {
|
|
return "projects"
|
|
}
|
|
|
|
// PrimaryKeyColumns implements the [pkRepository] interface
|
|
func (p project) PrimaryKeyColumns() []database.Column {
|
|
return []database.Column{
|
|
p.InstanceIDColumn(),
|
|
p.IDColumn(),
|
|
}
|
|
}
|
|
|
|
func (p project) InstanceIDColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "instance_id")
|
|
}
|
|
|
|
func (p project) OrganizationIDColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "organization_id")
|
|
}
|
|
|
|
func (p project) GrantedOrganizationIDColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "granted_organization_id")
|
|
}
|
|
|
|
func (p project) IDColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "id")
|
|
}
|
|
|
|
func (p project) CreatedAtColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "created_at")
|
|
}
|
|
|
|
func (p project) UpdatedAtColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "updated_at")
|
|
}
|
|
|
|
func (p project) NameColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "name")
|
|
}
|
|
|
|
func (p project) StateColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "state")
|
|
}
|
|
|
|
func (p project) ShouldAssertRoleColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "should_assert_role")
|
|
}
|
|
|
|
func (p project) IsAuthorizationRequiredColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "is_authorization_required")
|
|
}
|
|
|
|
func (p project) IsProjectAccessRequiredColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "is_project_access_required")
|
|
}
|
|
|
|
func (p project) UsedLabelingSettingOwnerColumn() database.Column {
|
|
return database.NewColumn(p.unqualifiedTableName(), "used_labeling_setting_owner")
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// helpers
|
|
// -------------------------------------------------------------
|
|
|
|
const queryProjectStmt = `SELECT
|
|
projects.instance_id,
|
|
projects.organization_id,
|
|
projects.id,
|
|
projects.created_at,
|
|
projects.updated_at,
|
|
projects.name,
|
|
projects.state,
|
|
projects.should_assert_role,
|
|
projects.is_authorization_required,
|
|
projects.is_project_access_required,
|
|
projects.used_labeling_setting_owner,
|
|
NULL::TEXT AS grant_id,
|
|
NULL::TEXT AS granted_organization_id,
|
|
NULL::zitadel.project_grant_state AS grant_state
|
|
FROM zitadel.projects`
|
|
|
|
func (p project) prepareGetQuery(opts []database.QueryOption) (*database.StatementBuilder, error) {
|
|
options := new(database.QueryOpts)
|
|
for _, opt := range opts {
|
|
opt(options)
|
|
}
|
|
if err := checkRestrictingColumns(options.Condition, p.InstanceIDColumn()); err != nil {
|
|
return nil, err
|
|
}
|
|
builder := database.NewStatementBuilder(queryProjectStmt)
|
|
options.Write(builder)
|
|
|
|
return builder, nil
|
|
}
|
|
|
|
const queryGrantedProjectStmt = `SELECT
|
|
projects.instance_id,
|
|
projects.organization_id,
|
|
projects.id as id,
|
|
grants.created_at,
|
|
grants.updated_at,
|
|
projects.name,
|
|
projects.state,
|
|
projects.should_assert_role,
|
|
projects.is_authorization_required,
|
|
projects.is_project_access_required,
|
|
projects.used_labeling_setting_owner,
|
|
grants.id AS grant_id,
|
|
grants.granted_organization_id,
|
|
grants.state as grant_state
|
|
FROM zitadel.projects
|
|
INNER JOIN zitadel.project_grants as grants
|
|
ON grants.instance_id = projects.instance_id
|
|
AND grants.granting_organization_id = projects.organization_id
|
|
AND grants.project_id = projects.id`
|
|
|
|
const queryProjectsUnionStmt = `SELECT
|
|
projects.instance_id,
|
|
projects.organization_id,
|
|
projects.id as id,
|
|
projects.created_at,
|
|
projects.updated_at,
|
|
projects.name,
|
|
projects.state,
|
|
projects.should_assert_role,
|
|
projects.is_authorization_required,
|
|
projects.is_project_access_required,
|
|
projects.used_labeling_setting_owner,
|
|
projects.grant_id,
|
|
projects.granted_organization_id,
|
|
projects.grant_state
|
|
FROM (` +
|
|
queryProjectStmt +
|
|
` UNION ALL ` +
|
|
queryGrantedProjectStmt +
|
|
`) AS projects`
|
|
|
|
func (p project) prepareListQuery(opts []database.QueryOption) (*database.StatementBuilder, error) {
|
|
options := new(database.QueryOpts)
|
|
for _, opt := range opts {
|
|
opt(options)
|
|
}
|
|
if err := checkRestrictingColumns(options.Condition, p.InstanceIDColumn()); err != nil {
|
|
return nil, err
|
|
}
|
|
builder := database.NewStatementBuilder(
|
|
queryProjectsUnionStmt,
|
|
)
|
|
options.Write(builder)
|
|
|
|
return builder, nil
|
|
}
|