chain of responsibilities

This commit is contained in:
adlerhurst
2025-02-26 09:49:38 +01:00
parent 16a324b8fd
commit fb3b451d4d
18 changed files with 86 additions and 35 deletions

View File

@@ -1,86 +0,0 @@
package cache
import (
"context"
"sync"
"github.com/zitadel/zitadel/backend/storage/cache"
"github.com/zitadel/zitadel/backend/storage/repository"
)
type Instance struct {
mu *sync.RWMutex
byID cache.Cache[string, *repository.Instance]
byDomain cache.Cache[string, *repository.Instance]
next repository.InstanceRepository
}
func (i *Instance) SetNext(next repository.InstanceRepository) *Instance {
return &Instance{
mu: i.mu,
byID: i.byID,
byDomain: i.byDomain,
next: next,
}
}
// ByDomain implements repository.InstanceRepository.
func (i *Instance) ByDomain(ctx context.Context, domain string) (instance *repository.Instance, err error) {
i.mu.RLock()
defer i.mu.RUnlock()
if instance, ok := i.byDomain.Get(domain); ok {
return instance, nil
}
instance, err = i.next.ByDomain(ctx, domain)
if err != nil {
return nil, err
}
i.set(instance, domain)
return instance, nil
}
// ByID implements repository.InstanceRepository.
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
i.mu.RLock()
defer i.mu.RUnlock()
if instance, ok := i.byID.Get(id); ok {
return instance, nil
}
instance, err := i.next.ByID(ctx, id)
if err != nil {
return nil, err
}
i.set(instance, "")
return instance, nil
}
// SetUp implements repository.InstanceRepository.
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
err := i.next.SetUp(ctx, instance)
if err != nil {
return err
}
i.set(instance, "")
return nil
}
var _ repository.InstanceRepository = (*Instance)(nil)
func (i *Instance) set(instance *repository.Instance, domain string) {
i.mu.Lock()
defer i.mu.Unlock()
if domain != "" {
i.byDomain.Set(domain, instance)
}
i.byID.Set(instance.ID, instance)
}

View File

@@ -1,45 +0,0 @@
package cache
import (
"context"
"github.com/zitadel/zitadel/backend/storage/cache"
"github.com/zitadel/zitadel/backend/storage/repository"
)
type User struct {
cache.Cache[string, *repository.User]
next repository.UserRepository
}
// ByID implements repository.UserRepository.
func (u *User) ByID(ctx context.Context, id string) (*repository.User, error) {
if user, ok := u.Get(id); ok {
return user, nil
}
user, err := u.next.ByID(ctx, id)
if err != nil {
return nil, err
}
u.set(user)
return user, nil
}
// Create implements repository.UserRepository.
func (u *User) Create(ctx context.Context, user *repository.User) error {
err := u.next.Create(ctx, user)
if err != nil {
return err
}
u.set(user)
return nil
}
var _ repository.UserRepository = (*User)(nil)
func (u *User) set(user *repository.User) {
u.Cache.Set(user.ID, user)
}

View File

@@ -1,37 +0,0 @@
package event
import (
"context"
"github.com/zitadel/zitadel/backend/storage/eventstore"
"github.com/zitadel/zitadel/backend/storage/repository"
)
var _ repository.InstanceRepository = (*Instance)(nil)
type Instance struct {
*eventstore.Eventstore
next repository.InstanceRepository
}
func NewInstance(eventstore *eventstore.Eventstore, next repository.InstanceRepository) *Instance {
return &Instance{next: next, Eventstore: eventstore}
}
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
return i.next.ByID(ctx, id)
}
func (i *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
return i.next.ByDomain(ctx, domain)
}
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
err := i.next.SetUp(ctx, instance)
if err != nil {
return err
}
return i.Push(ctx, instance)
}

View File

@@ -1,33 +0,0 @@
package event
import (
"context"
"github.com/zitadel/zitadel/backend/storage/eventstore"
"github.com/zitadel/zitadel/backend/storage/repository"
)
var _ repository.UserRepository = (*User)(nil)
type User struct {
*eventstore.Eventstore
next repository.UserRepository
}
func NewUser(eventstore *eventstore.Eventstore, next repository.UserRepository) *User {
return &User{next: next, Eventstore: eventstore}
}
func (i *User) ByID(ctx context.Context, id string) (*repository.User, error) {
return i.next.ByID(ctx, id)
}
func (i *User) Create(ctx context.Context, user *repository.User) error {
err := i.next.Create(ctx, user)
if err != nil {
return err
}
return i.Push(ctx, user)
}

View File

@@ -1,14 +0,0 @@
package repository
import "context"
type InstanceRepository interface {
SetUp(ctx context.Context, instance *Instance) error
ByID(ctx context.Context, id string) (*Instance, error)
ByDomain(ctx context.Context, domain string) (*Instance, error)
}
type Instance struct {
ID string
Name string
}

View File

@@ -1,45 +0,0 @@
package sql
import (
"context"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/storage/repository"
)
func NewInstance(client database.QueryExecutor) repository.InstanceRepository {
return &Instance{client: client}
}
type Instance struct {
client database.QueryExecutor
}
const instanceByDomainQuery = `SELECT i.id, i.name FROM instances i JOIN instance_domains id ON i.id = id.instance_id WHERE id.domain = $1`
// ByDomain implements [InstanceRepository].
func (r *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
row := r.client.QueryRow(ctx, instanceByDomainQuery, domain)
var instance repository.Instance
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
return nil, err
}
return &instance, nil
}
const instanceByIDQuery = `SELECT id, name FROM instances WHERE id = $1`
// ByID implements [InstanceRepository].
func (r *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
row := r.client.QueryRow(ctx, instanceByIDQuery, id)
var instance repository.Instance
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
return nil, err
}
return &instance, nil
}
// SetUp implements [InstanceRepository].
func (r *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
return r.client.Exec(ctx, "INSERT INTO instances (id, name) VALUES ($1, $2)", instance.ID, instance.Name)
}

View File

@@ -1,33 +0,0 @@
package sql
import (
"context"
"github.com/zitadel/zitadel/backend/storage/database"
"github.com/zitadel/zitadel/backend/storage/repository"
)
func NewUser(client database.QueryExecutor) repository.UserRepository {
return &User{client: client}
}
type User struct {
client database.QueryExecutor
}
const userByIDQuery = `SELECT id, username FROM users WHERE id = $1`
// ByID implements [UserRepository].
func (r *User) ByID(ctx context.Context, id string) (*repository.User, error) {
row := r.client.QueryRow(ctx, userByIDQuery, id)
var user repository.User
if err := row.Scan(&user.ID, &user.Username); err != nil {
return nil, err
}
return &user, nil
}
// Create implements [UserRepository].
func (r *User) Create(ctx context.Context, user *repository.User) error {
return r.client.Exec(ctx, "INSERT INTO users (id, username) VALUES ($1, $2)", user.ID, user.Username)
}

View File

@@ -1,40 +0,0 @@
package logged
import (
"context"
"log/slog"
"github.com/zitadel/zitadel/backend/storage/repository"
)
type Instance struct {
*slog.Logger
next repository.InstanceRepository
}
func NewInstance(logger *slog.Logger, next repository.InstanceRepository) *Instance {
return &Instance{Logger: logger, next: next}
}
var _ repository.InstanceRepository = (*Instance)(nil)
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
i.Logger.InfoContext(ctx, "By ID Query", slog.String("id", id))
return i.next.ByID(ctx, id)
}
func (i *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
i.Logger.InfoContext(ctx, "By Domain Query", slog.String("domain", domain))
return i.next.ByDomain(ctx, domain)
}
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) error {
err := i.next.SetUp(ctx, instance)
if err != nil {
i.Logger.ErrorContext(ctx, "Failed to set up instance", slog.Any("instance", instance), slog.Any("cause", err))
return err
}
i.Logger.InfoContext(ctx, "Instance set up", slog.Any("instance", instance))
return nil
}

View File

@@ -1,35 +0,0 @@
package logged
import (
"context"
"log/slog"
"github.com/zitadel/zitadel/backend/storage/repository"
)
type User struct {
*slog.Logger
next repository.UserRepository
}
func NewUser(logger *slog.Logger, next repository.UserRepository) *User {
return &User{Logger: logger, next: next}
}
var _ repository.UserRepository = (*User)(nil)
func (i *User) ByID(ctx context.Context, id string) (*repository.User, error) {
i.Logger.InfoContext(ctx, "By ID Query", slog.String("id", id))
return i.next.ByID(ctx, id)
}
func (i *User) Create(ctx context.Context, user *repository.User) error {
err := i.next.Create(ctx, user)
if err != nil {
i.Logger.ErrorContext(ctx, "Failed to create user", slog.Any("user", user), slog.Any("cause", err))
return err
}
i.Logger.InfoContext(ctx, "User created successfully", slog.Any("user", user))
return nil
}

View File

@@ -1,54 +0,0 @@
package traced
import (
"context"
"github.com/zitadel/zitadel/backend/storage/repository"
"github.com/zitadel/zitadel/backend/telemetry/tracing"
)
var _ repository.InstanceRepository = (*Instance)(nil)
type Instance struct {
*tracing.Tracer
next repository.InstanceRepository
}
func NewInstance(tracer *tracing.Tracer, next repository.InstanceRepository) *Instance {
return &Instance{Tracer: tracer, next: next}
}
func (i *Instance) SetNext(next repository.InstanceRepository) *Instance {
return &Instance{Tracer: i.Tracer, next: next}
}
// ByDomain implements [repository.InstanceRepository].
func (i *Instance) ByDomain(ctx context.Context, domain string) (instance *repository.Instance, err error) {
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
instance, err = i.next.ByDomain(ctx, domain)
return err
})
return instance, err
}
// ByID implements [repository.InstanceRepository].
func (i *Instance) ByID(ctx context.Context, id string) (instance *repository.Instance, err error) {
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
instance, err = i.next.ByID(ctx, id)
return err
})
return instance, err
}
// SetUp implements [repository.InstanceRepository].
func (i *Instance) SetUp(ctx context.Context, instance *repository.Instance) (err error) {
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
err = i.next.SetUp(ctx, instance)
return err
})
return err
}

View File

@@ -1,44 +0,0 @@
package traced
import (
"context"
"github.com/zitadel/zitadel/backend/storage/repository"
"github.com/zitadel/zitadel/backend/telemetry/tracing"
)
var _ repository.UserRepository = (*User)(nil)
type User struct {
*tracing.Tracer
next repository.UserRepository
}
func NewUser(tracer *tracing.Tracer, next repository.UserRepository) *User {
return &User{Tracer: tracer, next: next}
}
func (i *User) SetNext(next repository.UserRepository) *User {
return &User{Tracer: i.Tracer, next: next}
}
// ByID implements [repository.UserRepository].
func (i *User) ByID(ctx context.Context, id string) (user *repository.User, err error) {
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
user, err = i.next.ByID(ctx, id)
return err
})
return user, err
}
// Create implements [repository.UserRepository].
func (i *User) Create(ctx context.Context, user *repository.User) (err error) {
i.Tracer.Decorate(ctx, func(ctx context.Context) error {
err = i.next.Create(ctx, user)
return err
})
return err
}

View File

@@ -1,13 +0,0 @@
package repository
import "context"
type UserRepository interface {
Create(ctx context.Context, user *User) error
ByID(ctx context.Context, id string) (*User, error)
}
type User struct {
ID string
Username string
}