Files
zitadel/backend/v3/storage/database/errors.go
T
ca4bba3992 feat: add delete session on relation tables (#11334)
# Which Problems Are Solved

As part of moving the session API to the relational database, this PR
adds the functionality to delete sessions through the session API v2 and
the OIDC end_session endpoint.

# How the Problems Are Solved

- added `SessionDeleteCommand` in domain package
- added possibility to pass the session token verifier to the domain
package
- use feature flag to switch API and OIDC usage from CQRS to relation
table
- added a `permissionCheck` condition to let permissions be checked
directly in the repository / sql
- part of it is still a placeholder until actual permission tables are
done
- added a `session_deleted` table to store (recently) deleted sessions
to handle necessary checks / cases like delete my own session, which
needs to be idempotent

# Additional Changes

Fixed `Matches` function of `existsCondition` (as missing an
implementation)

# Additional Context

- closes #11037

---------

Co-authored-by: Stefan Benz <[email protected]>
2026-03-19 08:35:53 +01:00

298 lines
7.3 KiB
Go

package database
import (
"errors"
"fmt"
)
var (
ErrNoChanges = errors.New("update must contain a change")
ErrInvalidChangeTarget = errors.New("change target must not be nil")
)
type MissingConditionError struct {
col Column
}
func NewMissingConditionError(col Column) error {
return &MissingConditionError{
col: col,
}
}
func (e *MissingConditionError) Error() string {
var builder StatementBuilder
builder.WriteString("missing condition for column")
if e.col != nil {
builder.WriteString(" on ")
e.col.WriteQualified(&builder)
}
return builder.String()
}
func (e *MissingConditionError) Is(target error) bool {
_, ok := target.(*MissingConditionError)
return ok
}
// NoRowFoundError is returned when QueryRow does not find any row.
// It wraps the dialect specific original error to provide more context.
type NoRowFoundError struct {
original error
}
func NewNoRowFoundError(original error) error {
return &NoRowFoundError{
original: original,
}
}
func (e *NoRowFoundError) Error() string {
if e.original != nil {
return fmt.Sprintf("no row found: %v", e.original)
}
return "no row found"
}
func (e *NoRowFoundError) Is(target error) bool {
_, ok := target.(*NoRowFoundError)
return ok
}
func (e *NoRowFoundError) Unwrap() error {
return e.original
}
// MultipleRowsFoundError is returned when QueryRow finds multiple rows.
// It wraps the dialect specific original error to provide more context.
type MultipleRowsFoundError struct {
original error
}
func NewMultipleRowsFoundError(original error) error {
return &MultipleRowsFoundError{
original: original,
}
}
func (e *MultipleRowsFoundError) Error() string {
if e.original != nil {
return fmt.Sprintf("multiple rows found: %v", e.original)
}
return "multiple rows found"
}
func (e *MultipleRowsFoundError) Is(target error) bool {
_, ok := target.(*MultipleRowsFoundError)
return ok
}
func (e *MultipleRowsFoundError) Unwrap() error {
return e.original
}
type IntegrityType string
const (
IntegrityTypeCheck IntegrityType = "check"
IntegrityTypeUnique IntegrityType = "unique"
IntegrityTypeForeign IntegrityType = "foreign"
IntegrityTypeNotNull IntegrityType = "not null"
)
// IntegrityViolationError represents a generic integrity violation error.
// It wraps the dialect specific original error to provide more context.
type IntegrityViolationError struct {
integrityType IntegrityType
table string
constraint string
original error
}
func newIntegrityViolationError(typ IntegrityType, table, constraint string, original error) IntegrityViolationError {
return IntegrityViolationError{
integrityType: typ,
table: table,
constraint: constraint,
original: original,
}
}
func (e *IntegrityViolationError) Error() string {
if e.original != nil {
return fmt.Sprintf("integrity violation of type %q on %q (constraint: %q): %v", e.integrityType, e.table, e.constraint, e.original)
}
return fmt.Sprintf("integrity violation of type %q on %q (constraint: %q)", e.integrityType, e.table, e.constraint)
}
func (e *IntegrityViolationError) Is(target error) bool {
_, ok := target.(*IntegrityViolationError)
return ok
}
func (e *IntegrityViolationError) Unwrap() error {
return e.original
}
// CheckError is returned when a check constraint fails.
// It wraps the [IntegrityViolationError] to provide more context.
// It is used to indicate that a check constraint was violated during an insert or update operation.
type CheckError struct {
IntegrityViolationError
}
func NewCheckError(table, constraint string, original error) error {
return &CheckError{
IntegrityViolationError: newIntegrityViolationError(IntegrityTypeCheck, table, constraint, original),
}
}
func (e *CheckError) Is(target error) bool {
_, ok := target.(*CheckError)
return ok
}
func (e *CheckError) Unwrap() error {
return &e.IntegrityViolationError
}
// UniqueError is returned when a unique constraint fails.
// It wraps the [IntegrityViolationError] to provide more context.
// It is used to indicate that a unique constraint was violated during an insert or update operation.
type UniqueError struct {
IntegrityViolationError
}
func NewUniqueError(table, constraint string, original error) error {
return &UniqueError{
IntegrityViolationError: newIntegrityViolationError(IntegrityTypeUnique, table, constraint, original),
}
}
func (e *UniqueError) Is(target error) bool {
_, ok := target.(*UniqueError)
return ok
}
func (e *UniqueError) Unwrap() error {
return &e.IntegrityViolationError
}
// ForeignKeyError is returned when a foreign key constraint fails.
// It wraps the [IntegrityViolationError] to provide more context.
// It is used to indicate that a foreign key constraint was violated during an insert or update operation
type ForeignKeyError struct {
IntegrityViolationError
}
func NewForeignKeyError(table, constraint string, original error) error {
return &ForeignKeyError{
IntegrityViolationError: newIntegrityViolationError(IntegrityTypeForeign, table, constraint, original),
}
}
func (e *ForeignKeyError) Is(target error) bool {
_, ok := target.(*ForeignKeyError)
return ok
}
func (e *ForeignKeyError) Unwrap() error {
return &e.IntegrityViolationError
}
// NotNullError is returned when a not null constraint fails.
// It wraps the [IntegrityViolationError] to provide more context.
// It is used to indicate that a not null constraint was violated during an insert or update operation.
type NotNullError struct {
IntegrityViolationError
}
func NewNotNullError(table, constraint string, original error) error {
return &NotNullError{
IntegrityViolationError: newIntegrityViolationError(IntegrityTypeNotNull, table, constraint, original),
}
}
func (e *NotNullError) Is(target error) bool {
_, ok := target.(*NotNullError)
return ok
}
func (e *NotNullError) Unwrap() error {
return &e.IntegrityViolationError
}
// ScanError is returned when scanning rows into objects failed.
// It wraps the original error to provide more context.
type ScanError struct {
original error
}
func NewScanError(original error) error {
return &ScanError{
original: original,
}
}
func (e *ScanError) Error() string {
return fmt.Sprintf("Scan error: %v", e.original)
}
func (e *ScanError) Is(target error) bool {
_, ok := target.(*ScanError)
return ok
}
func (e *ScanError) Unwrap() error {
return e.original
}
// UnknownError is returned when an unknown error occurs.
// It wraps the dialect specific original error to provide more context.
// It is used to indicate that an error occurred that does not fit into any of the other categories.
type UnknownError struct {
original error
}
func NewUnknownError(original error) error {
return &UnknownError{
original: original,
}
}
func (e *UnknownError) Error() string {
return fmt.Sprintf("unknown database error: %v", e.original)
}
func (e *UnknownError) Is(target error) bool {
_, ok := target.(*UnknownError)
return ok
}
func (e *UnknownError) Unwrap() error {
return e.original
}
type PermissionError struct {
original error
}
func NewPermissionError(original error) error {
return &PermissionError{
original: original,
}
}
func (e *PermissionError) Error() string {
return fmt.Sprintf("permission error: %v", e.original)
}
func (e *PermissionError) Is(target error) bool {
_, ok := target.(*PermissionError)
return ok
}
func (e *PermissionError) Unwrap() error {
return e.original
}