mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 15:49:35 +00:00
add documentation
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
Copyright © 2025 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package main
|
||||
|
||||
|
@@ -1,12 +1,21 @@
|
||||
// the test used the manly relies on the following patterns:
|
||||
// - api:
|
||||
// - some example stubs for the grpc api, it maps the calls and responses to the domain objects
|
||||
//
|
||||
// - domain:
|
||||
// - hexagonal architecture, it defines its dependencies as interfaces and the dependencies must use the objects defined by this package
|
||||
// - command pattern which implements the changes
|
||||
// - the invoker decorates the commands by checking for events and tracing
|
||||
// - the invoker decorates the commands by checking for events, tracing, logging, potentially caching, etc.
|
||||
// - the database connections are manged in this package
|
||||
// - the database connections are passed to the repositories
|
||||
//
|
||||
// - storage:
|
||||
// - repository pattern, the repositories are defined as interfaces and the implementations are in the storage package
|
||||
// - the repositories are used by the domain package to access the database
|
||||
// - the eventstore to store events. At the beginning it writes to the same events table as the /internal package, afterwards it writes to a different table
|
||||
//
|
||||
// - telemetry:
|
||||
// - logging for standard output
|
||||
// - tracing for distributed tracing
|
||||
// - metrics for monitoring
|
||||
package v3
|
||||
|
@@ -7,15 +7,22 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
)
|
||||
|
||||
// Commander is the all it needs to implement the command pattern.
|
||||
// It is the interface all manipulations need to implement.
|
||||
// If possible it should also be used for queries. We will find out if this is possible in the future.
|
||||
type Commander interface {
|
||||
Execute(ctx context.Context, opts *CommandOpts) (err error)
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
// Invoker is part of the command pattern.
|
||||
// It is the interface that is used to execute commands.
|
||||
type Invoker interface {
|
||||
Invoke(ctx context.Context, command Commander, opts *CommandOpts) error
|
||||
}
|
||||
|
||||
// CommandOpts are passed to each command
|
||||
// the provide common fields used by commands like the database client.
|
||||
type CommandOpts struct {
|
||||
DB database.QueryExecutor
|
||||
Invoker Invoker
|
||||
@@ -95,6 +102,8 @@ func DefaultOpts(invoker Invoker) *CommandOpts {
|
||||
}
|
||||
}
|
||||
|
||||
// commandBatch is a batch of commands.
|
||||
// It uses the [Invoker] provided by the opts to execute each command.
|
||||
type commandBatch struct {
|
||||
Commands []Commander
|
||||
}
|
||||
|
@@ -6,6 +6,10 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/eventstore"
|
||||
)
|
||||
|
||||
// CreateUserCommand adds a new user including the email verification for humans.
|
||||
// In the future it might make sense to separate the command into two commands:
|
||||
// - CreateHumanCommand: creates a new human user
|
||||
// - CreateMachineCommand: creates a new machine user
|
||||
type CreateUserCommand struct {
|
||||
user *User
|
||||
email *SetEmailCommand
|
||||
@@ -16,6 +20,7 @@ var (
|
||||
_ eventer = (*CreateUserCommand)(nil)
|
||||
)
|
||||
|
||||
// opts heavily reduces the complexity for email verification because each type of verification is a simple option which implements the [Commander] interface.
|
||||
func NewCreateHumanCommand(username string, opts ...CreateHumanOpt) *CreateUserCommand {
|
||||
cmd := &CreateUserCommand{
|
||||
user: &User{
|
||||
|
@@ -11,6 +11,10 @@ type generateCodeCommand struct {
|
||||
value *crypto.CryptoValue
|
||||
}
|
||||
|
||||
// I didn't update this repository to the solution proposed please view one of the following interfaces for correct usage:
|
||||
// - [UserRepository]
|
||||
// - [InstanceRepository]
|
||||
// - [OrgRepository]
|
||||
type CryptoRepository interface {
|
||||
GetEncryptionConfig(ctx context.Context) (*crypto.GeneratorConfig, error)
|
||||
}
|
||||
|
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
)
|
||||
|
||||
// The variables could also be moved to a struct.
|
||||
// I just started with the singleton pattern and kept it like this.
|
||||
var (
|
||||
pool database.Pool
|
||||
userCodeAlgorithm crypto.EncryptionAlgorithm
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/telemetry/tracing"
|
||||
)
|
||||
|
||||
// These tests give an overview of how to use the domain package.
|
||||
func TestExample(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// EmailVerifiedCommand verifies an email address for a user.
|
||||
type EmailVerifiedCommand struct {
|
||||
UserID string `json:"userId"`
|
||||
Email *Email `json:"email"`
|
||||
@@ -42,6 +43,8 @@ func (cmd *EmailVerifiedCommand) applyOnSetEmail(setEmailCmd *SetEmailCommand) {
|
||||
setEmailCmd.verification = cmd
|
||||
}
|
||||
|
||||
// SendCodeCommand sends a verification code to the user's email address.
|
||||
// If the URLTemplate is not set it will use the default of the organization / instance.
|
||||
type SendCodeCommand struct {
|
||||
UserID string `json:"userId"`
|
||||
Email string `json:"email"`
|
||||
@@ -113,6 +116,8 @@ func (cmd *SendCodeCommand) applyOnSetEmail(setEmailCmd *SetEmailCommand) {
|
||||
setEmailCmd.verification = cmd
|
||||
}
|
||||
|
||||
// ReturnCodeCommand creates the code and returns it to the caller.
|
||||
// The caller gets the code by calling the Code field after the command got executed.
|
||||
type ReturnCodeCommand struct {
|
||||
UserID string `json:"userId"`
|
||||
Email string `json:"email"`
|
||||
|
@@ -33,6 +33,7 @@ func (i *Instance) Keys(index instanceCacheIndex) (key []string) {
|
||||
|
||||
var _ cache.Entry[instanceCacheIndex, string] = (*Instance)(nil)
|
||||
|
||||
// instanceColumns define all the columns of the instance table.
|
||||
type instanceColumns interface {
|
||||
// IDColumn returns the column for the id field.
|
||||
IDColumn() database.Column
|
||||
@@ -46,6 +47,7 @@ type instanceColumns interface {
|
||||
DeletedAtColumn() database.Column
|
||||
}
|
||||
|
||||
// instanceConditions define all the conditions for the instance table.
|
||||
type instanceConditions interface {
|
||||
// IDCondition returns an equal filter on the id field.
|
||||
IDCondition(instanceID string) database.Condition
|
||||
@@ -53,16 +55,19 @@ type instanceConditions interface {
|
||||
NameCondition(op database.TextOperation, name string) database.Condition
|
||||
}
|
||||
|
||||
// instanceChanges define all the changes for the instance table.
|
||||
type instanceChanges interface {
|
||||
// SetName sets the name column.
|
||||
SetName(name string) database.Change
|
||||
}
|
||||
|
||||
// InstanceRepository is the interface for the instance repository.
|
||||
type InstanceRepository interface {
|
||||
instanceColumns
|
||||
instanceConditions
|
||||
instanceChanges
|
||||
|
||||
// Member returns the member repository which is a sub repository of the instance repository.
|
||||
Member() MemberRepository
|
||||
|
||||
Get(ctx context.Context, opts ...database.QueryOption) (*Instance, error)
|
||||
|
@@ -7,6 +7,10 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/eventstore"
|
||||
)
|
||||
|
||||
// Invoke provides a way to execute commands within the domain package.
|
||||
// It uses a chain of responsibility pattern to handle the command execution.
|
||||
// The default chain includes logging, tracing, and event publishing.
|
||||
// If you want to invoke multiple commands in a single transaction, you can use the [commandBatch].
|
||||
func Invoke(ctx context.Context, cmd Commander) error {
|
||||
invoker := newEventStoreInvoker(newLoggingInvoker(newTraceInvoker(nil)))
|
||||
opts := &CommandOpts{
|
||||
@@ -16,6 +20,8 @@ func Invoke(ctx context.Context, cmd Commander) error {
|
||||
return invoker.Invoke(ctx, cmd, opts)
|
||||
}
|
||||
|
||||
// eventStoreInvoker checks if the command implements the [eventer] interface.
|
||||
// If it does, it collects the events and publishes them to the event store.
|
||||
type eventStoreInvoker struct {
|
||||
collector *eventCollector
|
||||
}
|
||||
@@ -38,6 +44,7 @@ func (i *eventStoreInvoker) Invoke(ctx context.Context, command Commander, opts
|
||||
return nil
|
||||
}
|
||||
|
||||
// eventCollector collects events from all commands. The [eventStoreInvoker] pushes the collected events after all commands are executed.
|
||||
type eventCollector struct {
|
||||
next Invoker
|
||||
events []*eventstore.Event
|
||||
@@ -64,6 +71,7 @@ func (i *eventCollector) Invoke(ctx context.Context, command Commander, opts *Co
|
||||
return command.Execute(ctx, opts)
|
||||
}
|
||||
|
||||
// traceInvoker decorates each command with tracing.
|
||||
type traceInvoker struct {
|
||||
next Invoker
|
||||
}
|
||||
@@ -87,6 +95,8 @@ func (i *traceInvoker) Invoke(ctx context.Context, command Commander, opts *Comm
|
||||
return command.Execute(ctx, opts)
|
||||
}
|
||||
|
||||
// loggingInvoker decorates each command with logging.
|
||||
// It is an example implementation and logs the command name at the beginning and success or failure after the command got executed.
|
||||
type loggingInvoker struct {
|
||||
next Invoker
|
||||
}
|
||||
@@ -123,6 +133,10 @@ func (i *noopInvoker) Invoke(ctx context.Context, command Commander, opts *Comma
|
||||
return command.Execute(ctx, opts)
|
||||
}
|
||||
|
||||
// cacheInvoker could be used in the future to do the caching.
|
||||
// My goal would be to have two interfaces:
|
||||
// - cacheSetter: which caches an object
|
||||
// - cacheGetter: which gets an object from the cache, this should also skip the command execution
|
||||
type cacheInvoker struct {
|
||||
next Invoker
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ const (
|
||||
OrgStateInactive
|
||||
)
|
||||
|
||||
// Org is used by all other packages to represent an organization.
|
||||
type Org struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -42,6 +43,7 @@ func (o *Org) Keys(index orgCacheIndex) (key []string) {
|
||||
|
||||
var _ cache.Entry[orgCacheIndex, string] = (*Org)(nil)
|
||||
|
||||
// orgColumns define all the columns of the org table.
|
||||
type orgColumns interface {
|
||||
// InstanceIDColumn returns the column for the instance id field.
|
||||
InstanceIDColumn() database.Column
|
||||
@@ -59,6 +61,7 @@ type orgColumns interface {
|
||||
DeletedAtColumn() database.Column
|
||||
}
|
||||
|
||||
// orgConditions define all the conditions for the org table.
|
||||
type orgConditions interface {
|
||||
// InstanceIDCondition returns an equal filter on the instance id field.
|
||||
InstanceIDCondition(instanceID string) database.Condition
|
||||
@@ -70,6 +73,7 @@ type orgConditions interface {
|
||||
StateCondition(op database.NumberOperation, state OrgState) database.Condition
|
||||
}
|
||||
|
||||
// orgChanges define all the changes for the org table.
|
||||
type orgChanges interface {
|
||||
// SetName sets the name column.
|
||||
SetName(name string) database.Change
|
||||
@@ -77,12 +81,14 @@ type orgChanges interface {
|
||||
SetState(state OrgState) database.Change
|
||||
}
|
||||
|
||||
// OrgRepository is the interface for the org repository.
|
||||
// It is used to interact with the org table in the database.
|
||||
type OrgRepository interface {
|
||||
orgColumns
|
||||
orgConditions
|
||||
orgChanges
|
||||
|
||||
// Member returns the admin repository.
|
||||
// Member returns the member repository.
|
||||
Member() MemberRepository
|
||||
// Domain returns the domain repository.
|
||||
Domain() DomainRepository
|
||||
@@ -99,19 +105,14 @@ type OrgRepository interface {
|
||||
Update(ctx context.Context, condition database.Condition, changes ...database.Change) error
|
||||
}
|
||||
|
||||
type OrgOperation interface {
|
||||
MemberRepository
|
||||
DomainRepository
|
||||
Update(ctx context.Context, org *Org) error
|
||||
Delete(ctx context.Context) error
|
||||
}
|
||||
|
||||
// MemberRepository is a sub repository of the org repository and maybe the instance repository.
|
||||
type MemberRepository interface {
|
||||
AddMember(ctx context.Context, orgID, userID string, roles []string) error
|
||||
SetMemberRoles(ctx context.Context, orgID, userID string, roles []string) error
|
||||
RemoveMember(ctx context.Context, orgID, userID string) error
|
||||
}
|
||||
|
||||
// DomainRepository is a sub repository of the org repository and maybe the instance repository.
|
||||
type DomainRepository interface {
|
||||
AddDomain(ctx context.Context, domain string) error
|
||||
SetDomainVerified(ctx context.Context, domain string) error
|
||||
|
@@ -6,6 +6,8 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/eventstore"
|
||||
)
|
||||
|
||||
// AddOrgCommand adds a new organization.
|
||||
// I'm unsure if we should add the Admins here or if this should be a separate command.
|
||||
type AddOrgCommand struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -86,6 +88,8 @@ func (cmd *AddOrgCommand) ensureID() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// AddMemberCommand adds a new member to an organization.
|
||||
// I'm not sure if we should make it more generic to also use it for instances.
|
||||
type AddMemberCommand struct {
|
||||
orgID string
|
||||
UserID string `json:"userId"`
|
||||
|
@@ -6,6 +6,10 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/eventstore"
|
||||
)
|
||||
|
||||
// SetEmailCommand sets the email address of a user.
|
||||
// If allows verification as a sub command.
|
||||
// The verification command is executed after the email address is set.
|
||||
// The verification command is executed in the same transaction as the email address update.
|
||||
type SetEmailCommand struct {
|
||||
UserID string `json:"userId"`
|
||||
Email string `json:"email"`
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
)
|
||||
|
||||
// userColumns define all the columns of the user table.
|
||||
type userColumns interface {
|
||||
// InstanceIDColumn returns the column for the instance id field.
|
||||
InstanceIDColumn() database.Column
|
||||
@@ -24,6 +25,7 @@ type userColumns interface {
|
||||
DeletedAtColumn() database.Column
|
||||
}
|
||||
|
||||
// userConditions define all the conditions for the user table.
|
||||
type userConditions interface {
|
||||
// InstanceIDCondition returns an equal filter on the instance id field.
|
||||
InstanceIDCondition(instanceID string) database.Condition
|
||||
@@ -43,11 +45,13 @@ type userConditions interface {
|
||||
DeletedAtCondition(op database.NumberOperation, deletedAt time.Time) database.Condition
|
||||
}
|
||||
|
||||
// userChanges define all the changes for the user table.
|
||||
type userChanges interface {
|
||||
// SetUsername sets the username column.
|
||||
SetUsername(username string) database.Change
|
||||
}
|
||||
|
||||
// UserRepository is the interface for the user repository.
|
||||
type UserRepository interface {
|
||||
userColumns
|
||||
userConditions
|
||||
@@ -66,6 +70,7 @@ type UserRepository interface {
|
||||
Machine() MachineRepository
|
||||
}
|
||||
|
||||
// humanColumns define all the columns of the human table which inherits the user table.
|
||||
type humanColumns interface {
|
||||
userColumns
|
||||
// FirstNameColumn returns the column for the first name field.
|
||||
@@ -82,6 +87,7 @@ type humanColumns interface {
|
||||
PhoneVerifiedAtColumn() database.Column
|
||||
}
|
||||
|
||||
// humanConditions define all the conditions for the human table which inherits the user table.
|
||||
type humanConditions interface {
|
||||
userConditions
|
||||
// FirstNameCondition returns a filter on the first name field.
|
||||
@@ -103,6 +109,7 @@ type humanConditions interface {
|
||||
PhoneVerifiedAtCondition(op database.NumberOperation, phoneVerifiedAt time.Time) database.Condition
|
||||
}
|
||||
|
||||
// humanChanges define all the changes for the human table which inherits the user table.
|
||||
type humanChanges interface {
|
||||
userChanges
|
||||
// SetFirstName sets the first name field of the human.
|
||||
@@ -129,6 +136,7 @@ type humanChanges interface {
|
||||
SetPhoneVerifiedAt(at time.Time) database.Change
|
||||
}
|
||||
|
||||
// HumanRepository is the interface for the human repository it inherits the user repository.
|
||||
type HumanRepository interface {
|
||||
humanColumns
|
||||
humanConditions
|
||||
@@ -140,24 +148,28 @@ type HumanRepository interface {
|
||||
Update(ctx context.Context, condition database.Condition, changes ...database.Change) error
|
||||
}
|
||||
|
||||
// machineColumns define all the columns of the machine table which inherits the user table.
|
||||
type machineColumns interface {
|
||||
userColumns
|
||||
// DescriptionColumn returns the column for the description field.
|
||||
DescriptionColumn() database.Column
|
||||
}
|
||||
|
||||
// machineConditions define all the conditions for the machine table which inherits the user table.
|
||||
type machineConditions interface {
|
||||
userConditions
|
||||
// DescriptionCondition returns a filter on the description field.
|
||||
DescriptionCondition(op database.TextOperation, description string) database.Condition
|
||||
}
|
||||
|
||||
// machineChanges define all the changes for the machine table which inherits the user table.
|
||||
type machineChanges interface {
|
||||
userChanges
|
||||
// SetDescription sets the description field of the machine.
|
||||
SetDescription(description string) database.Change
|
||||
}
|
||||
|
||||
// MachineRepository is the interface for the machine repository it inherits the user repository.
|
||||
type MachineRepository interface {
|
||||
// Update updates machine users based on the given condition and changes.
|
||||
Update(ctx context.Context, condition database.Condition, changes ...database.Change) error
|
||||
@@ -167,6 +179,7 @@ type MachineRepository interface {
|
||||
machineChanges
|
||||
}
|
||||
|
||||
// UserTraits is implemented by [Human] and [Machine].
|
||||
type UserTraits interface {
|
||||
Type() UserType
|
||||
}
|
||||
|
2
backend/v3/storage/cache/doc.go
vendored
Normal file
2
backend/v3/storage/cache/doc.go
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// this package is copy pasted from the internal/cache package
|
||||
package cache
|
@@ -1,5 +1,7 @@
|
||||
package database
|
||||
|
||||
// Change represents a change to a column in a database table.
|
||||
// Its written in the SET clause of an UPDATE statement.
|
||||
type Change interface {
|
||||
Write(builder *StatementBuilder)
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ func (m Columns) Write(builder *StatementBuilder) {
|
||||
}
|
||||
}
|
||||
|
||||
// Column represents a column in a database table.
|
||||
type Column interface {
|
||||
Write(builder *StatementBuilder)
|
||||
}
|
||||
@@ -31,6 +32,8 @@ func (c column) Write(builder *StatementBuilder) {
|
||||
|
||||
var _ Column = (*column)(nil)
|
||||
|
||||
// ignoreCaseColumn represents two database columns, one for the
|
||||
// original value and one for the lower case value.
|
||||
type ignoreCaseColumn interface {
|
||||
Column
|
||||
WriteIgnoreCase(builder *StatementBuilder)
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package database
|
||||
|
||||
// Condition represents a SQL condition.
|
||||
// Its written after the WHERE keyword in a SQL statement.
|
||||
type Condition interface {
|
||||
Write(builder *StatementBuilder)
|
||||
}
|
||||
@@ -22,6 +24,7 @@ func (a *and) Write(builder *StatementBuilder) {
|
||||
}
|
||||
}
|
||||
|
||||
// And combines multiple conditions with AND.
|
||||
func And(conditions ...Condition) *and {
|
||||
return &and{conditions: conditions}
|
||||
}
|
||||
@@ -46,6 +49,7 @@ func (o *or) Write(builder *StatementBuilder) {
|
||||
}
|
||||
}
|
||||
|
||||
// Or combines multiple conditions with OR.
|
||||
func Or(conditions ...Condition) *or {
|
||||
return &or{conditions: conditions}
|
||||
}
|
||||
@@ -62,6 +66,7 @@ func (i *isNull) Write(builder *StatementBuilder) {
|
||||
builder.WriteString(" IS NULL")
|
||||
}
|
||||
|
||||
// IsNull creates a condition that checks if a column is NULL.
|
||||
func IsNull(column Column) *isNull {
|
||||
return &isNull{column: column}
|
||||
}
|
||||
@@ -78,6 +83,7 @@ func (i *isNotNull) Write(builder *StatementBuilder) {
|
||||
builder.WriteString(" IS NOT NULL")
|
||||
}
|
||||
|
||||
// IsNotNull creates a condition that checks if a column is NOT NULL.
|
||||
func IsNotNull(column Column) *isNotNull {
|
||||
return &isNotNull{column: column.(Column)}
|
||||
}
|
||||
@@ -86,18 +92,21 @@ var _ Condition = (*isNotNull)(nil)
|
||||
|
||||
type valueCondition func(builder *StatementBuilder)
|
||||
|
||||
// NewTextCondition creates a condition that compares a text column with a value.
|
||||
func NewTextCondition[V Text](col Column, op TextOperation, value V) Condition {
|
||||
return valueCondition(func(builder *StatementBuilder) {
|
||||
writeTextOperation(builder, col, op, value)
|
||||
})
|
||||
}
|
||||
|
||||
// NewDateCondition creates a condition that compares a numeric column with a value.
|
||||
func NewNumberCondition[V Number](col Column, op NumberOperation, value V) Condition {
|
||||
return valueCondition(func(builder *StatementBuilder) {
|
||||
writeNumberOperation(builder, col, op, value)
|
||||
})
|
||||
}
|
||||
|
||||
// NewDateCondition creates a condition that compares a boolean column with a value.
|
||||
func NewBooleanCondition[V Boolean](col Column, value V) Condition {
|
||||
return valueCondition(func(builder *StatementBuilder) {
|
||||
writeBooleanOperation(builder, col, value)
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Connector abstracts the database driver.
|
||||
type Connector interface {
|
||||
Connect(ctx context.Context) (Pool, error)
|
||||
}
|
||||
|
@@ -4,15 +4,7 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
var (
|
||||
db *database
|
||||
)
|
||||
|
||||
type database struct {
|
||||
connector Connector
|
||||
pool Pool
|
||||
}
|
||||
|
||||
// Pool is a connection pool. e.g. pgxpool
|
||||
type Pool interface {
|
||||
Beginner
|
||||
QueryExecutor
|
||||
@@ -21,6 +13,7 @@ type Pool interface {
|
||||
Close(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Client is a single database connection which can be released back to the pool.
|
||||
type Client interface {
|
||||
Beginner
|
||||
QueryExecutor
|
||||
@@ -28,33 +21,37 @@ type Client interface {
|
||||
Release(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Querier is a database client that can execute queries and return rows.
|
||||
type Querier interface {
|
||||
Query(ctx context.Context, stmt string, args ...any) (Rows, error)
|
||||
QueryRow(ctx context.Context, stmt string, args ...any) Row
|
||||
}
|
||||
|
||||
// Executor is a database client that can execute statements.
|
||||
type Executor interface {
|
||||
Exec(ctx context.Context, stmt string, args ...any) error
|
||||
}
|
||||
|
||||
// QueryExecutor is a database client that can execute queries and statements.
|
||||
type QueryExecutor interface {
|
||||
Querier
|
||||
Executor
|
||||
}
|
||||
|
||||
// Scanner scans a single row of data into the destination.
|
||||
type Scanner interface {
|
||||
Scan(dest ...any) error
|
||||
}
|
||||
|
||||
// Row is an abstraction of sql.Row.
|
||||
type Row interface {
|
||||
Scanner
|
||||
}
|
||||
|
||||
// Rows is an abstraction of sql.Rows.
|
||||
type Rows interface {
|
||||
Row
|
||||
Next() bool
|
||||
Close() error
|
||||
Err() error
|
||||
}
|
||||
|
||||
type Query[T any] func(querier Querier) (result T, err error)
|
||||
|
2
backend/v3/storage/database/dialect/postgres/doc.go
Normal file
2
backend/v3/storage/database/dialect/postgres/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// pgxpool v5 implementation of the interfaces defined in the database package.
|
||||
package postgres
|
@@ -18,6 +18,7 @@ type Text interface {
|
||||
~string | ~[]byte
|
||||
}
|
||||
|
||||
// TextOperation are operations that can be performed on text values.
|
||||
type TextOperation uint8
|
||||
|
||||
const (
|
||||
@@ -89,6 +90,7 @@ type Number interface {
|
||||
constraints.Integer | constraints.Float | constraints.Complex | time.Time | time.Duration
|
||||
}
|
||||
|
||||
// NumberOperation are operations that can be performed on number values.
|
||||
type NumberOperation uint8
|
||||
|
||||
const (
|
||||
@@ -125,6 +127,7 @@ type Boolean interface {
|
||||
~bool
|
||||
}
|
||||
|
||||
// BooleanOperation are operations that can be performed on boolean values.
|
||||
type BooleanOperation uint8
|
||||
|
||||
const (
|
||||
|
5
backend/v3/storage/database/repository/doc.go
Normal file
5
backend/v3/storage/database/repository/doc.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// Package implements the repositories defined in the domain package.
|
||||
// The repositories are used by the domain package to access the database.
|
||||
// the inheritance.sql file is me over-engineering table inheritance.
|
||||
// I would create a user table which is inherited by human_user and machine_user and the same for objects like idps.
|
||||
package repository
|
@@ -2,6 +2,7 @@ package database
|
||||
|
||||
import "context"
|
||||
|
||||
// Transaction is an SQL transaction.
|
||||
type Transaction interface {
|
||||
Commit(ctx context.Context) error
|
||||
Rollback(ctx context.Context) error
|
||||
@@ -12,6 +13,7 @@ type Transaction interface {
|
||||
QueryExecutor
|
||||
}
|
||||
|
||||
// Beginner can start a new transaction.
|
||||
type Beginner interface {
|
||||
Begin(ctx context.Context, opts *TransactionOptions) (Transaction, error)
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package logging
|
||||
|
||||
import "log/slog"
|
||||
|
||||
// Logger abstracts [slog.Logger] not sure if thats needed
|
||||
type Logger struct {
|
||||
*slog.Logger
|
||||
}
|
||||
|
2
backend/v3/telemetry/metric/doc.go
Normal file
2
backend/v3/telemetry/metric/doc.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// implementation of otel metrics
|
||||
package metric
|
@@ -7,6 +7,7 @@ import (
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
// Tracer is a wrapper around the OpenTelemetry Tracer interface.
|
||||
type Tracer struct {
|
||||
trace.Tracer
|
||||
}
|
||||
|
Reference in New Issue
Block a user