mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:17:32 +00:00
not that bad anymore
This commit is contained in:
@@ -13,7 +13,8 @@ import (
|
|||||||
type Instance struct {
|
type Instance struct {
|
||||||
db database.Pool
|
db database.Pool
|
||||||
|
|
||||||
orchestrator instanceOrchestrator
|
instance instanceOrchestrator
|
||||||
|
user userOrchestrator
|
||||||
}
|
}
|
||||||
|
|
||||||
type instanceOrchestrator interface {
|
type instanceOrchestrator interface {
|
||||||
@@ -24,19 +25,20 @@ type instanceOrchestrator interface {
|
|||||||
|
|
||||||
func NewInstance(db database.Pool, tracer *tracing.Tracer, logger *logging.Logger) *Instance {
|
func NewInstance(db database.Pool, tracer *tracing.Tracer, logger *logging.Logger) *Instance {
|
||||||
b := &Instance{
|
b := &Instance{
|
||||||
db: db,
|
db: db,
|
||||||
orchestrator: orchestrate.Instance(),
|
instance: orchestrate.Instance(),
|
||||||
|
user: orchestrate.User(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
func (b *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
||||||
return b.orchestrator.ByID(ctx, b.db, id)
|
return b.instance.ByID(ctx, b.db, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
func (b *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
||||||
return b.orchestrator.ByDomain(ctx, b.db, domain)
|
return b.instance.ByDomain(ctx, b.db, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetUpInstance struct {
|
type SetUpInstance struct {
|
||||||
@@ -52,9 +54,10 @@ func (b *Instance) SetUp(ctx context.Context, request *SetUpInstance) (err error
|
|||||||
defer func() {
|
defer func() {
|
||||||
err = tx.End(ctx, err)
|
err = tx.End(ctx, err)
|
||||||
}()
|
}()
|
||||||
_, err = b.orchestrator.SetUp(ctx, tx, request.Instance)
|
_, err = b.instance.SetUp(ctx, tx, request.Instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return b.userCommandRepo(tx).Create(ctx, request.User)
|
_, err = b.user.Create(ctx, tx, request.User)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -1,39 +1,13 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/repository/event"
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/sql"
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/telemetry/logged"
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/telemetry/traced"
|
|
||||||
"github.com/zitadel/zitadel/backend/storage/database"
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Instance) userCommandRepo(tx database.Transaction) repository.UserRepository {
|
type userOrchestrator interface {
|
||||||
return logged.NewUser(
|
Create(ctx context.Context, client database.Transaction, user *repository.User) (*repository.User, error)
|
||||||
b.logger,
|
ByID(ctx context.Context, querier database.Querier, id string) (*repository.User, error)
|
||||||
traced.NewUser(
|
|
||||||
b.tracer,
|
|
||||||
event.NewUser(
|
|
||||||
eventstore.New(tx),
|
|
||||||
sql.NewUser(tx),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Instance) userQueryRepo(tx database.QueryExecutor) repository.UserRepository {
|
|
||||||
return logged.NewUser(
|
|
||||||
b.logger,
|
|
||||||
traced.NewUser(
|
|
||||||
b.tracer,
|
|
||||||
sql.NewUser(tx),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
ID string
|
|
||||||
Username string
|
|
||||||
}
|
}
|
||||||
|
92
backend/repository/cache/instance.go
vendored
92
backend/repository/cache/instance.go
vendored
@@ -5,8 +5,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
|
||||||
"github.com/zitadel/zitadel/backend/storage/cache"
|
"github.com/zitadel/zitadel/backend/storage/cache"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/cache/gomap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
@@ -15,85 +15,31 @@ type Instance struct {
|
|||||||
byDomain cache.Cache[string, *repository.Instance]
|
byDomain cache.Cache[string, *repository.Instance]
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetUpInstance(
|
func NewInstance() *Instance {
|
||||||
cache *Instance,
|
return &Instance{
|
||||||
handle handler.Handle[*repository.Instance, *repository.Instance],
|
mu: &sync.RWMutex{},
|
||||||
) handler.Handle[*repository.Instance, *repository.Instance] {
|
byID: gomap.New[string, *repository.Instance](),
|
||||||
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
byDomain: gomap.New[string, *repository.Instance](),
|
||||||
instance, err := handle(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.set(instance, "")
|
|
||||||
return instance, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetUpInstanceWithout(cache *Instance) handler.Handle[*repository.Instance, *repository.Instance] {
|
func (i *Instance) Set(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
i.set(instance, "")
|
||||||
cache.set(instance, "")
|
return instance, nil
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetUpInstanceDecorated(
|
func (i *Instance) ByID(ctx context.Context, id string) (*repository.Instance, error) {
|
||||||
cache *Instance,
|
i.mu.RLock()
|
||||||
handle handler.Handle[*repository.Instance, *repository.Instance],
|
defer i.mu.RUnlock()
|
||||||
decorator handler.Decorate[*repository.Instance, *repository.Instance],
|
instance, _ := i.byID.Get(id)
|
||||||
) handler.Handle[*repository.Instance, *repository.Instance] {
|
return instance, nil
|
||||||
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
|
||||||
instance, err := handle(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return decorator(ctx, instance, func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
|
||||||
cache.set(instance, "")
|
|
||||||
return instance, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ForInstanceByID(cache *Instance, handle handler.Handle[string, *repository.Instance]) handler.Handle[string, *repository.Instance] {
|
func (i *Instance) ByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
||||||
return func(ctx context.Context, id string) (*repository.Instance, error) {
|
i.mu.RLock()
|
||||||
cache.mu.RLock()
|
defer i.mu.RUnlock()
|
||||||
|
instance, _ := i.byDomain.Get(domain)
|
||||||
instance, ok := cache.byID.Get(id)
|
return instance, nil
|
||||||
cache.mu.RUnlock()
|
|
||||||
if ok {
|
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
instance, err := handle(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.set(instance, "")
|
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ForInstanceByDomain(cache *Instance, handle handler.Handle[string, *repository.Instance]) handler.Handle[string, *repository.Instance] {
|
|
||||||
return func(ctx context.Context, domain string) (*repository.Instance, error) {
|
|
||||||
cache.mu.RLock()
|
|
||||||
|
|
||||||
instance, ok := cache.byDomain.Get(domain)
|
|
||||||
cache.mu.RUnlock()
|
|
||||||
if ok {
|
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
instance, err := handle(ctx, domain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cache.set(instance, domain)
|
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Instance) set(instance *repository.Instance, domain string) {
|
func (i *Instance) set(instance *repository.Instance, domain string) {
|
||||||
|
30
backend/repository/cache/user.go
vendored
30
backend/repository/cache/user.go
vendored
@@ -5,41 +5,31 @@ import (
|
|||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/storage/cache"
|
"github.com/zitadel/zitadel/backend/storage/cache"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/cache/gomap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
cache.Cache[string, *repository.User]
|
cache.Cache[string, *repository.User]
|
||||||
|
}
|
||||||
|
|
||||||
next repository.UserRepository
|
func NewUser() *User {
|
||||||
|
return &User{
|
||||||
|
Cache: gomap.New[string, *repository.User](),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByID implements repository.UserRepository.
|
// ByID implements repository.UserRepository.
|
||||||
func (u *User) ByID(ctx context.Context, id string) (*repository.User, error) {
|
func (u *User) ByID(ctx context.Context, id string) (*repository.User, error) {
|
||||||
if user, ok := u.Get(id); ok {
|
user, _ := u.Get(id)
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
|
||||||
|
|
||||||
user, err := u.next.ByID(ctx, id)
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func (u *User) Set(ctx context.Context, user *repository.User) (*repository.User, error) {
|
||||||
u.set(user)
|
u.set(user)
|
||||||
return user, nil
|
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) {
|
func (u *User) set(user *repository.User) {
|
||||||
u.Cache.Set(user.ID, user)
|
u.Cache.Set(user.ID, user)
|
||||||
}
|
}
|
||||||
|
@@ -4,59 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
|
||||||
"github.com/zitadel/zitadel/backend/storage/database"
|
|
||||||
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetUpInstance(
|
func (s *store) CreateInstance(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
client database.Executor,
|
err := s.es.Push(ctx, instance)
|
||||||
next handler.Handle[*repository.Instance, *repository.Instance],
|
if err != nil {
|
||||||
) handler.Handle[*repository.Instance, *repository.Instance] {
|
return nil, err
|
||||||
es := eventstore.New(client)
|
|
||||||
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
|
||||||
instance, err := next(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = es.Push(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetUpInstanceWithout(client database.Executor) handler.Handle[*repository.Instance, *repository.Instance] {
|
|
||||||
es := eventstore.New(client)
|
|
||||||
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
|
||||||
err := es.Push(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return instance, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetUpInstanceDecorated(
|
|
||||||
client database.Executor,
|
|
||||||
next handler.Handle[*repository.Instance, *repository.Instance],
|
|
||||||
decorate handler.Decorate[*repository.Instance, *repository.Instance],
|
|
||||||
) handler.Handle[*repository.Instance, *repository.Instance] {
|
|
||||||
es := eventstore.New(client)
|
|
||||||
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
|
||||||
instance, err := next(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return decorate(ctx, instance, func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
|
||||||
err = es.Push(ctx, instance)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return instance, nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
16
backend/repository/event/store.go
Normal file
16
backend/repository/event/store.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package event
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
||||||
|
)
|
||||||
|
|
||||||
|
type store struct {
|
||||||
|
es *eventstore.Eventstore
|
||||||
|
}
|
||||||
|
|
||||||
|
func Store(client database.Executor) *store {
|
||||||
|
return &store{
|
||||||
|
es: eventstore.New(client),
|
||||||
|
}
|
||||||
|
}
|
@@ -4,30 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/storage/eventstore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ repository.UserRepository = (*User)(nil)
|
func (s *store) CreateUser(ctx context.Context, user *repository.User) (*repository.User, error) {
|
||||||
|
err := s.es.Push(ctx, user)
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return user, nil
|
||||||
return i.Push(ctx, user)
|
|
||||||
}
|
}
|
||||||
|
64
backend/repository/orchestrate/handler/handle.go
Normal file
64
backend/repository/orchestrate/handler/handle.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Handler is a function that handles the request.
|
||||||
|
type Handler[Req, Res any] func(ctx context.Context, request Req) (res Res, err error)
|
||||||
|
|
||||||
|
// Decorator is a function that decorates the handle function.
|
||||||
|
type Decorator[Req, Res any] func(ctx context.Context, request Req, handle Handler[Req, Res]) (res Res, err error)
|
||||||
|
|
||||||
|
// Chain chains the handle function with the next handler.
|
||||||
|
// The next handler is called after the handle function.
|
||||||
|
func Chain[Req, Res any](handle Handler[Req, Res], next Handler[Res, Res]) Handler[Req, Res] {
|
||||||
|
return func(ctx context.Context, request Req) (res Res, err error) {
|
||||||
|
res, err = handle(ctx, request)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return next(ctx, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorate decorates the handle function with the decorate function.
|
||||||
|
// The decorate function is called before the handle function.
|
||||||
|
func Decorate[Req, Res any](handle Handler[Req, Res], decorate Decorator[Req, Res]) Handler[Req, Res] {
|
||||||
|
return func(ctx context.Context, request Req) (res Res, err error) {
|
||||||
|
return decorate(ctx, request, handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorates decorates the handle function with the decorate function.
|
||||||
|
// The decorate function is called before the handle function.
|
||||||
|
func Decorates[Req, Res any](handle Handler[Req, Res], decorates ...Decorator[Req, Res]) Handler[Req, Res] {
|
||||||
|
return func(ctx context.Context, request Req) (res Res, err error) {
|
||||||
|
for _, decorate := range decorates {
|
||||||
|
handle = Decorate(handle, decorate)
|
||||||
|
}
|
||||||
|
return handle(ctx, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipNext skips the next handler if the handle function returns a non-nil response.
|
||||||
|
func SkipNext[Req, Res any](handle Handler[Req, Res], next Handler[Req, Res]) Handler[Req, Res] {
|
||||||
|
return func(ctx context.Context, request Req) (res Res, err error) {
|
||||||
|
var empty Res
|
||||||
|
res, err = handle(ctx, request)
|
||||||
|
// TODO: does this work?
|
||||||
|
if any(res) == any(empty) || err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return next(ctx, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipNilHandler skips the handle function if the handler is nil.
|
||||||
|
// The function is safe to call with nil handler.
|
||||||
|
func SkipNilHandler[O, R any](handler *O, handle Handler[R, R]) Handler[R, R] {
|
||||||
|
return func(ctx context.Context, request R) (res R, err error) {
|
||||||
|
if handler == nil {
|
||||||
|
return request, nil
|
||||||
|
}
|
||||||
|
return handle(ctx, request)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,26 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type Handle[Req, Res any] func(ctx context.Context, request Req) (res Res, err error)
|
|
||||||
|
|
||||||
type Decorate[Req, Res any] func(ctx context.Context, request Req, handle Handle[Req, Res]) (res Res, err error)
|
|
||||||
|
|
||||||
func NewChained[Req, Res any](handle Handle[Req, Res], next Handle[Res, Res]) Handle[Req, Res] {
|
|
||||||
return func(ctx context.Context, request Req) (res Res, err error) {
|
|
||||||
res, err = handle(ctx, request)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
if next == nil {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
return next(ctx, res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDecorated[Req, Res any](decorate Decorate[Req, Res], handle Handle[Req, Res]) Handle[Req, Res] {
|
|
||||||
return func(ctx context.Context, request Req) (res Res, err error) {
|
|
||||||
return decorate(ctx, request, handle)
|
|
||||||
}
|
|
||||||
}
|
|
@@ -33,40 +33,51 @@ func (i *instance) apply(o Option) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *instance) SetUp(ctx context.Context, tx database.Transaction, instance *repository.Instance) (*repository.Instance, error) {
|
func (i *instance) SetUp(ctx context.Context, tx database.Transaction, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
return handler.NewChained(
|
return traced.Wrap(i.tracer, "instance.SetUp",
|
||||||
handler.NewDecorated(
|
handler.Chain(
|
||||||
traced.DecorateHandle[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.sql.SetUp")),
|
handler.Decorates(
|
||||||
sql.SetUpInstance(tx),
|
sql.Execute(tx).CreateInstance,
|
||||||
),
|
traced.Decorate[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.sql.SetUp")),
|
||||||
handler.NewChained(
|
logged.Decorate[*repository.Instance, *repository.Instance](i.logger, "instance.sql.SetUp"),
|
||||||
handler.NewDecorated(
|
|
||||||
traced.DecorateHandle[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.event.SetUp")),
|
|
||||||
event.SetUpInstanceWithout(tx),
|
|
||||||
),
|
),
|
||||||
handler.NewDecorated(
|
handler.Chain(
|
||||||
traced.DecorateHandle[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.cache.SetUp")),
|
handler.Decorates(
|
||||||
cache.SetUpInstanceWithout(i.cache),
|
event.Store(tx).CreateInstance,
|
||||||
|
traced.Decorate[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.event.SetUp")),
|
||||||
|
logged.Decorate[*repository.Instance, *repository.Instance](i.logger, "instance.event.SetUp"),
|
||||||
|
),
|
||||||
|
handler.Decorates(
|
||||||
|
handler.SkipNilHandler(i.cache, i.cache.Set),
|
||||||
|
traced.Decorate[*repository.Instance, *repository.Instance](i.tracer, tracing.WithSpanName("instance.cache.SetUp")),
|
||||||
|
logged.Decorate[*repository.Instance, *repository.Instance](i.logger, "instance.cache.SetUp"),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)(ctx, instance)
|
)(ctx, instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *instance) ByID(ctx context.Context, querier database.Querier, id string) (*repository.Instance, error) {
|
func (i *instance) ByID(ctx context.Context, querier database.Querier, id string) (*repository.Instance, error) {
|
||||||
return traced.Wrap(i.tracer, "instance.byID",
|
return handler.SkipNext(
|
||||||
logged.Wrap(i.logger, "instance.byID",
|
i.cache.ByID,
|
||||||
cache.ForInstanceByID(i.cache,
|
handler.Chain(
|
||||||
sql.InstanceByID(querier),
|
handler.Decorate(
|
||||||
|
sql.Query(querier).InstanceByID,
|
||||||
|
traced.Decorate[string, *repository.Instance](i.tracer, tracing.WithSpanName("instance.sql.ByID")),
|
||||||
),
|
),
|
||||||
|
handler.SkipNilHandler(i.cache, i.cache.Set),
|
||||||
),
|
),
|
||||||
)(ctx, id)
|
)(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *instance) ByDomain(ctx context.Context, querier database.Querier, domain string) (*repository.Instance, error) {
|
func (i *instance) ByDomain(ctx context.Context, querier database.Querier, domain string) (*repository.Instance, error) {
|
||||||
return traced.Wrap(i.tracer, "instance.byDomain",
|
return handler.SkipNext(
|
||||||
logged.Wrap(i.logger, "instance.byDomain",
|
i.cache.ByDomain,
|
||||||
cache.ForInstanceByDomain(i.cache,
|
handler.Chain(
|
||||||
sql.InstanceByDomain(querier),
|
handler.Decorate(
|
||||||
|
sql.Query(querier).InstanceByDomain,
|
||||||
|
traced.Decorate[string, *repository.Instance](i.tracer, tracing.WithSpanName("instance.sql.ByDomain")),
|
||||||
),
|
),
|
||||||
|
handler.SkipNilHandler(i.cache, i.cache.Set),
|
||||||
),
|
),
|
||||||
)(ctx, domain)
|
)(ctx, domain)
|
||||||
}
|
}
|
||||||
|
75
backend/repository/orchestrate/instance_test.go
Normal file
75
backend/repository/orchestrate/instance_test.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package orchestrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/cache"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database/mock"
|
||||||
|
"github.com/zitadel/zitadel/backend/telemetry/logging"
|
||||||
|
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_instance_SetUp(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
options options
|
||||||
|
cache *cache.Instance
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
tx database.Transaction
|
||||||
|
instance *repository.Instance
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want *repository.Instance
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple",
|
||||||
|
fields: fields{
|
||||||
|
options: options{
|
||||||
|
tracer: tracing.NewTracer("test"),
|
||||||
|
logger: logging.New(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))),
|
||||||
|
},
|
||||||
|
cache: cache.NewInstance(),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
tx: mock.NewTransaction(),
|
||||||
|
instance: &repository.Instance{
|
||||||
|
ID: "ID",
|
||||||
|
Name: "Name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &repository.Instance{
|
||||||
|
ID: "ID",
|
||||||
|
Name: "Name",
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
i := &instance{
|
||||||
|
options: tt.fields.options,
|
||||||
|
cache: tt.fields.cache,
|
||||||
|
}
|
||||||
|
got, err := i.SetUp(tt.args.ctx, tt.args.tx, tt.args.instance)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("instance.SetUp() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("instance.SetUp() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
60
backend/repository/orchestrate/user.go
Normal file
60
backend/repository/orchestrate/user.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package orchestrate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/cache"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/event"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/sql"
|
||||||
|
"github.com/zitadel/zitadel/backend/repository/telemetry/traced"
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
|
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type user struct {
|
||||||
|
options
|
||||||
|
|
||||||
|
cache *cache.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func User(opts ...Option) *user {
|
||||||
|
i := new(user)
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&i.options)
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *user) apply(o Option) {
|
||||||
|
o(&i.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *user) Create(ctx context.Context, tx database.Transaction, user *repository.User) (*repository.User, error) {
|
||||||
|
return traced.Wrap(i.tracer, "user.Create",
|
||||||
|
handler.Chain(
|
||||||
|
handler.Decorate(
|
||||||
|
sql.Execute(tx).CreateUser,
|
||||||
|
traced.Decorate[*repository.User, *repository.User](i.tracer, tracing.WithSpanName("user.sql.Create")),
|
||||||
|
),
|
||||||
|
handler.Decorate(
|
||||||
|
event.Store(tx).CreateUser,
|
||||||
|
traced.Decorate[*repository.User, *repository.User](i.tracer, tracing.WithSpanName("user.event.Create")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)(ctx, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *user) ByID(ctx context.Context, querier database.Querier, id string) (*repository.User, error) {
|
||||||
|
return handler.SkipNext(
|
||||||
|
i.cache.ByID,
|
||||||
|
handler.Chain(
|
||||||
|
handler.Decorate(
|
||||||
|
sql.Query(querier).UserByID,
|
||||||
|
traced.Decorate[string, *repository.User](i.tracer, tracing.WithSpanName("user.sql.ByID")),
|
||||||
|
),
|
||||||
|
handler.SkipNilHandler(i.cache, i.cache.Set),
|
||||||
|
),
|
||||||
|
)(ctx, id)
|
||||||
|
}
|
21
backend/repository/sql/client.go
Normal file
21
backend/repository/sql/client.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package sql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
type executor[C database.Executor] struct {
|
||||||
|
client C
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute[C database.Executor](client C) *executor[C] {
|
||||||
|
return &executor[C]{client: client}
|
||||||
|
}
|
||||||
|
|
||||||
|
type querier[C database.Querier] struct {
|
||||||
|
client C
|
||||||
|
}
|
||||||
|
|
||||||
|
func Query[C database.Querier](client C) *querier[C] {
|
||||||
|
return &querier[C]{client: client}
|
||||||
|
}
|
@@ -4,42 +4,53 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
|
||||||
"github.com/zitadel/zitadel/backend/storage/database"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const instanceByDomainQuery = `SELECT i.id, i.name FROM instances i JOIN instance_domains id ON i.id = id.instance_id WHERE id.domain = $1`
|
|
||||||
|
|
||||||
func InstanceByDomain(client database.Querier) handler.Handle[string, *repository.Instance] {
|
|
||||||
return func(ctx context.Context, domain string) (*repository.Instance, error) {
|
|
||||||
row := 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`
|
const instanceByIDQuery = `SELECT id, name FROM instances WHERE id = $1`
|
||||||
|
|
||||||
func InstanceByID(client database.Querier) handler.Handle[string, *repository.Instance] {
|
func (q *querier[C]) InstanceByID(ctx context.Context, id string) (*repository.Instance, error) {
|
||||||
return func(ctx context.Context, id string) (*repository.Instance, error) {
|
row := q.client.QueryRow(ctx, instanceByIDQuery, id)
|
||||||
row := client.QueryRow(ctx, instanceByIDQuery, id)
|
var instance repository.Instance
|
||||||
var instance repository.Instance
|
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
|
||||||
if err := row.Scan(&instance.ID, &instance.Name); err != nil {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &instance, nil
|
|
||||||
}
|
}
|
||||||
|
return &instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetUpInstance(tx database.Transaction) handler.Handle[*repository.Instance, *repository.Instance] {
|
const instanceByDomainQuery = `SELECT i.id, i.name FROM instances i JOIN instance_domains id ON i.id = id.instance_id WHERE id.domain = $1`
|
||||||
return func(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
|
||||||
err := tx.Exec(ctx, "INSERT INTO instances (id, name) VALUES ($1, $2)", instance.ID, instance.Name)
|
func (q *querier[C]) InstanceByDomain(ctx context.Context, domain string) (*repository.Instance, error) {
|
||||||
if err != nil {
|
row := q.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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *querier[C]) ListInstances(ctx context.Context, request *repository.ListRequest) (res []*repository.Instance, err error) {
|
||||||
|
rows, err := q.client.Query(ctx, "SELECT id, name FROM instances")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
var instance repository.Instance
|
||||||
|
if err = rows.Scan(&instance.ID, &instance.Name); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return instance, nil
|
res = append(res, &instance)
|
||||||
}
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *executor[C]) CreateInstance(ctx context.Context, instance *repository.Instance) (*repository.Instance, error) {
|
||||||
|
err := e.client.Exec(ctx, "INSERT INTO instances (id, name) VALUES ($1, $2)", instance.ID, instance.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
@@ -4,22 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository"
|
"github.com/zitadel/zitadel/backend/repository"
|
||||||
"github.com/zitadel/zitadel/backend/storage/database"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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`
|
const userByIDQuery = `SELECT id, username FROM users WHERE id = $1`
|
||||||
|
|
||||||
// ByID implements [UserRepository].
|
func (q *querier[C]) UserByID(ctx context.Context, id string) (res *repository.User, err error) {
|
||||||
func (r *User) ByID(ctx context.Context, id string) (*repository.User, error) {
|
row := q.client.QueryRow(ctx, userByIDQuery, id)
|
||||||
row := r.client.QueryRow(ctx, userByIDQuery, id)
|
|
||||||
var user repository.User
|
var user repository.User
|
||||||
if err := row.Scan(&user.ID, &user.Username); err != nil {
|
if err := row.Scan(&user.ID, &user.Username); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -27,7 +17,10 @@ func (r *User) ByID(ctx context.Context, id string) (*repository.User, error) {
|
|||||||
return &user, nil
|
return &user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create implements [UserRepository].
|
func (e *executor[C]) CreateUser(ctx context.Context, user *repository.User) (res *repository.User, err error) {
|
||||||
func (r *User) Create(ctx context.Context, user *repository.User) error {
|
err = e.client.Exec(ctx, "INSERT INTO users (id, username) VALUES ($1, $2)", user.ID, user.Username)
|
||||||
return r.client.Exec(ctx, "INSERT INTO users (id, username) VALUES ($1, $2)", user.ID, user.Username)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return user, nil
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
// Wrap decorates the given handle function with logging.
|
// Wrap decorates the given handle function with logging.
|
||||||
// The function is safe to call with nil logger.
|
// The function is safe to call with nil logger.
|
||||||
func Wrap[Req, Res any](logger *logging.Logger, name string, handle handler.Handle[Req, Res]) handler.Handle[Req, Res] {
|
func Wrap[Req, Res any](logger *logging.Logger, name string, handle handler.Handler[Req, Res]) handler.Handler[Req, Res] {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
return handle
|
return handle
|
||||||
}
|
}
|
||||||
@@ -21,23 +21,11 @@ func Wrap[Req, Res any](logger *logging.Logger, name string, handle handler.Hand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapInside(logger *logging.Logger, name string) func(ctx context.Context, fn func(context.Context) error) {
|
// Decorate decorates the given handle function with logging.
|
||||||
logger = logger.With(slog.String("handler", name))
|
// The function is safe to call with nil logger.
|
||||||
return func(ctx context.Context, fn func(context.Context) error) {
|
func Decorate[Req, Res any](logger *logging.Logger, name string) handler.Decorator[Req, Res] {
|
||||||
logger.Debug("execute")
|
logger = logger.With("handler", name)
|
||||||
var err error
|
return func(ctx context.Context, request Req, handle handler.Handler[Req, Res]) (res Res, err error) {
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("failed", slog.String("cause", err.Error()))
|
|
||||||
}
|
|
||||||
logger.Debug("done")
|
|
||||||
}()
|
|
||||||
err = fn(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecorateHandle[Req, Res any](logger *logging.Logger, handle func(context.Context, Req) (Res, error)) func(ctx context.Context, r Req) (_ Res, err error) {
|
|
||||||
return func(ctx context.Context, r Req) (_ Res, err error) {
|
|
||||||
logger.DebugContext(ctx, "execute")
|
logger.DebugContext(ctx, "execute")
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,24 +33,6 @@ func DecorateHandle[Req, Res any](logger *logging.Logger, handle func(context.Co
|
|||||||
}
|
}
|
||||||
logger.DebugContext(ctx, "done")
|
logger.DebugContext(ctx, "done")
|
||||||
}()
|
}()
|
||||||
return handle(ctx, r)
|
return handle(ctx, request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Handler wraps the given handle function with logging.
|
|
||||||
// // The function is safe to call with nil logger.
|
|
||||||
// func Handler[Req, Res any, H handler.Handle[Req, Res]](logger *logging.Logger, name string, handle H) *handler.Handler[Req, Res, H] {
|
|
||||||
// return &handler.Handler[Req, Res, H]{
|
|
||||||
// Handle: Wrap(logger, name, handle),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Chained wraps the given handle function with logging.
|
|
||||||
// // The function is safe to call with nil logger.
|
|
||||||
// // The next handler is called after the handle function.
|
|
||||||
// func Chained[Req, Res any, H, N handler.Handle[Req, Res]](logger *logging.Logger, name string, handle H, next N) *handler.Chained[Req, Res, H, N] {
|
|
||||||
// return handler.NewChained(
|
|
||||||
// Wrap(logger, name, handle),
|
|
||||||
// next,
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
@@ -2,6 +2,7 @@ package traced
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
"github.com/zitadel/zitadel/backend/repository/orchestrate/handler"
|
||||||
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
"github.com/zitadel/zitadel/backend/telemetry/tracing"
|
||||||
@@ -9,7 +10,7 @@ import (
|
|||||||
|
|
||||||
// Wrap decorates the given handle function with tracing.
|
// Wrap decorates the given handle function with tracing.
|
||||||
// The function is safe to call with nil tracer.
|
// The function is safe to call with nil tracer.
|
||||||
func Wrap[Req, Res any](tracer *tracing.Tracer, name string, handle handler.Handle[Req, Res]) handler.Handle[Req, Res] {
|
func Wrap[Req, Res any](tracer *tracing.Tracer, name string, handle handler.Handler[Req, Res]) handler.Handler[Req, Res] {
|
||||||
if tracer == nil {
|
if tracer == nil {
|
||||||
return handle
|
return handle
|
||||||
}
|
}
|
||||||
@@ -28,50 +29,18 @@ func Wrap[Req, Res any](tracer *tracing.Tracer, name string, handle handler.Hand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapInside(tracer *tracing.Tracer, name string) func(ctx context.Context, fn func() error) {
|
// Decorate decorates the given handle function with tracing.
|
||||||
return func(ctx context.Context, fn func() error) {
|
// The function is safe to call with nil tracer.
|
||||||
var err error
|
func Decorate[Req, Res any](tracer *tracing.Tracer, opts ...tracing.DecorateOption) handler.Decorator[Req, Res] {
|
||||||
_, span := tracer.Start(
|
return func(ctx context.Context, r Req, handle handler.Handler[Req, Res]) (_ Res, err error) {
|
||||||
ctx,
|
|
||||||
name,
|
|
||||||
)
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
span.RecordError(err)
|
|
||||||
}
|
|
||||||
span.End()
|
|
||||||
}()
|
|
||||||
err = fn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecorateHandle[Req, Res any](tracer *tracing.Tracer, opts ...tracing.DecorateOption) handler.Decorate[Req, Res] {
|
|
||||||
return func(ctx context.Context, r Req, handle handler.Handle[Req, Res]) (_ Res, err error) {
|
|
||||||
o := new(tracing.DecorateOptions)
|
o := new(tracing.DecorateOptions)
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(o)
|
opt(o)
|
||||||
}
|
}
|
||||||
|
log.Println("trace")
|
||||||
|
|
||||||
ctx = o.Start(ctx, tracer)
|
ctx, end := o.Start(ctx, tracer)
|
||||||
defer o.End(err)
|
defer end(err)
|
||||||
return handle(ctx, r)
|
return handle(ctx, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Handler wraps the given handle function with tracing.
|
|
||||||
// // The function is safe to call with nil logger.
|
|
||||||
// func Handler[Req, Res any, H handler.Handle[Req, Res]](tracer *tracing.Tracer, name string, handle H) *handler.Handler[Req, Res, H] {
|
|
||||||
// return &handler.Handler[Req, Res, H]{
|
|
||||||
// Handle: Wrap(tracer, name, handle),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Chained wraps the given handle function with tracing.
|
|
||||||
// // The function is safe to call with nil logger.
|
|
||||||
// // The next handler is called after the handle function.
|
|
||||||
// func Chained[Req, Res any, H, N handler.Handle[Req, Res]](tracer *tracing.Tracer, name string, handle H, next N) *handler.Chained[Req, Res, H, N] {
|
|
||||||
// return handler.NewChained(
|
|
||||||
// Wrap(tracer, name, handle),
|
|
||||||
// next,
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
@@ -1,12 +1,5 @@
|
|||||||
package repository
|
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 {
|
type User struct {
|
||||||
ID string
|
ID string
|
||||||
Username string
|
Username string
|
||||||
|
7
backend/storage/cache/gomap/map.go
vendored
7
backend/storage/cache/gomap/map.go
vendored
@@ -11,6 +11,13 @@ type Map[K comparable, V any] struct {
|
|||||||
items map[K]V
|
items map[K]V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func New[K comparable, V any]() *Map[K, V] {
|
||||||
|
return &Map[K, V]{
|
||||||
|
items: make(map[K]V),
|
||||||
|
mu: sync.RWMutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clear implements cache.Cache.
|
// Clear implements cache.Cache.
|
||||||
func (m *Map[K, V]) Clear() {
|
func (m *Map[K, V]) Clear() {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
|
67
backend/storage/database/mock/transaction.go
Normal file
67
backend/storage/database/mock/transaction.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package mock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/backend/storage/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Transaction struct {
|
||||||
|
committed bool
|
||||||
|
rolledBack bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransaction() *Transaction {
|
||||||
|
return new(Transaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit implements [database.Transaction].
|
||||||
|
func (t *Transaction) Commit(ctx context.Context) error {
|
||||||
|
if t.hasEnded() {
|
||||||
|
return errors.New("transaction already committed or rolled back")
|
||||||
|
}
|
||||||
|
t.committed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// End implements [database.Transaction].
|
||||||
|
func (t *Transaction) End(ctx context.Context, err error) error {
|
||||||
|
if t.hasEnded() {
|
||||||
|
return errors.New("transaction already committed or rolled back")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return t.Rollback(ctx)
|
||||||
|
}
|
||||||
|
return t.Commit(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec implements [database.Transaction].
|
||||||
|
func (t *Transaction) Exec(ctx context.Context, sql string, args ...any) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query implements [database.Transaction].
|
||||||
|
func (t *Transaction) Query(ctx context.Context, sql string, args ...any) (database.Rows, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryRow implements [database.Transaction].
|
||||||
|
func (t *Transaction) QueryRow(ctx context.Context, sql string, args ...any) database.Row {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rollback implements [database.Transaction].
|
||||||
|
func (t *Transaction) Rollback(ctx context.Context) error {
|
||||||
|
if t.hasEnded() {
|
||||||
|
return errors.New("transaction already committed or rolled back")
|
||||||
|
}
|
||||||
|
t.rolledBack = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ database.Transaction = (*Transaction)(nil)
|
||||||
|
|
||||||
|
func (t *Transaction) hasEnded() bool {
|
||||||
|
return t.committed || t.rolledBack
|
||||||
|
}
|
@@ -6,6 +6,10 @@ type Logger struct {
|
|||||||
*slog.Logger
|
*slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func New(l *slog.Logger) *Logger {
|
||||||
|
return &Logger{Logger: l}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Logger) With(args ...any) *Logger {
|
func (l *Logger) With(args ...any) *Logger {
|
||||||
return &Logger{l.Logger.With(args...)}
|
return &Logger{l.Logger.With(args...)}
|
||||||
}
|
}
|
||||||
|
@@ -10,8 +10,8 @@ import (
|
|||||||
|
|
||||||
type Tracer struct{ trace.Tracer }
|
type Tracer struct{ trace.Tracer }
|
||||||
|
|
||||||
func NewTracer(name string) Tracer {
|
func NewTracer(name string) *Tracer {
|
||||||
return Tracer{otel.Tracer(name)}
|
return &Tracer{otel.Tracer(name)}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DecorateOption func(*DecorateOptions)
|
type DecorateOption func(*DecorateOptions)
|
||||||
@@ -43,15 +43,15 @@ func WithSpanEndOptions(opts ...trace.SpanEndOption) DecorateOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *DecorateOptions) Start(ctx context.Context, tracer *Tracer) context.Context {
|
func (o *DecorateOptions) Start(ctx context.Context, tracer *Tracer) (context.Context, func(error)) {
|
||||||
if o.spanName == "" {
|
if o.spanName == "" {
|
||||||
o.spanName = functionName()
|
o.spanName = functionName()
|
||||||
}
|
}
|
||||||
ctx, o.span = tracer.Tracer.Start(ctx, o.spanName, o.startOpts...)
|
ctx, o.span = tracer.Tracer.Start(ctx, o.spanName, o.startOpts...)
|
||||||
return ctx
|
return ctx, o.end
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *DecorateOptions) End(err error) {
|
func (o *DecorateOptions) end(err error) {
|
||||||
o.span.RecordError(err)
|
o.span.RecordError(err)
|
||||||
o.span.End(o.endOpts...)
|
o.span.End(o.endOpts...)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user