mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-19 22:14:25 +00:00
# Which Problems Are Solved As part of going to a relation storage model, we need to implement the repository for handling sessions and their events. # How the Problems Are Solved - Adds a migration step to create the necessary tables and types in the database. - Adds the repository implementation for sessions. - Implements a projection handler for session events to handle the events written by the old command handlers. - Updates the `Session` type and `SessionRepository` interface: - added `CreatorID` - Adjusted `Delete` method to return amount of affected columns - Removed sub-repository clumns from the main interface - Added `CreatorIDCondition`, `ExpirationCondition`, `ExistsFactor` and `ExistsMetadata` - Removed `SetUserAgent` - Methods of `SessionFactor` and `SessionChallenge` have been made public - fixed enumer on `SessionFactorType` - Adds a `JSON` type to the repository package to easy can JSON columns, resp. jsonb object inside a property of a `JSONArray` object. - Adds a `NoChange` interface, which can be implemented to signal that a `Change` interface implementation is not writing any changes to the statement builder, e.g. `CTEChange` # Additional Changes - Fixes the operators enums. `TextOperations` had wrong comments and `NumberOperations` additionally also had from comparisons. - Fixes downgrade of migration step 008. # Additional Context - closes https://github.com/zitadel/zitadel/issues/10212
187 lines
5.9 KiB
Go
187 lines
5.9 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"golang.org/x/exp/constraints"
|
|
)
|
|
|
|
type wrappedValue[V Value] struct {
|
|
value V
|
|
fn function
|
|
}
|
|
|
|
func LowerValue[T Value](v T) wrappedValue[T] {
|
|
return wrappedValue[T]{value: v, fn: functionLower}
|
|
}
|
|
|
|
func SHA256Value[T Value](v T) wrappedValue[T] {
|
|
return wrappedValue[T]{value: v, fn: functionSHA256}
|
|
}
|
|
|
|
func (b wrappedValue[V]) WriteArg(builder *StatementBuilder) {
|
|
builder.Grow(len(b.fn) + 5)
|
|
builder.WriteString(string(b.fn))
|
|
builder.WriteRune('(')
|
|
builder.WriteArg(b.value)
|
|
builder.WriteRune(')')
|
|
}
|
|
|
|
var _ argWriter = (*wrappedValue[string])(nil)
|
|
|
|
type Value interface {
|
|
Boolean | Number | Text | Instruction | Bytes
|
|
}
|
|
|
|
//go:generate enumer -type NumberOperation,TextOperation,BytesOperation -linecomment -output ./operators_enumer.go
|
|
type Operation interface {
|
|
NumberOperation | TextOperation | BytesOperation
|
|
}
|
|
|
|
type Text interface {
|
|
~string | Bytes
|
|
}
|
|
|
|
// TextOperation are operations that can be performed on text values.
|
|
type TextOperation uint8
|
|
|
|
const (
|
|
// TextOperationEqual compares two strings for equality.
|
|
TextOperationEqual TextOperation = iota + 1 // =
|
|
// TextOperationNotEqual compares two strings for inequality.
|
|
TextOperationNotEqual // <>
|
|
// TextOperationStartsWith checks if the first string starts with the second.
|
|
TextOperationStartsWith // LIKE
|
|
// TextOperationContains checks if the first string contains the second
|
|
TextOperationContains // LIKE
|
|
// TextOperationEndsWith checks if the first string ends with the second.
|
|
TextOperationEndsWith // LIKE
|
|
|
|
// TextOperationContainsIgnoreCase checks if the first string contains the second ignoring case
|
|
TextOperationContainsIgnoreCase // LIKE
|
|
// TextOperationEndsWithIgnoreCase checks if the first string ends with the second ignoring case
|
|
TextOperationEndsWithIgnoreCase // LIKE
|
|
// TextOperationStartsWithIgnoreCase checks if the first string starts with the second ignoring case
|
|
TextOperationStartsWithIgnoreCase // LIKE
|
|
// TextOperationEqualIgnoreCase compares two strings for equality ignoring case
|
|
TextOperationEqualIgnoreCase // =
|
|
// TextOperationNotEqualIgnoreCase compares two strings for inequality ignoring case
|
|
TextOperationNotEqualIgnoreCase // <>
|
|
)
|
|
|
|
func (op TextOperation) IsIgnoreCaseOperation() bool {
|
|
return op == TextOperationContainsIgnoreCase ||
|
|
op == TextOperationEndsWithIgnoreCase ||
|
|
op == TextOperationStartsWithIgnoreCase ||
|
|
op == TextOperationEqualIgnoreCase ||
|
|
op == TextOperationNotEqualIgnoreCase
|
|
}
|
|
|
|
func (op TextOperation) Value() TextOperation {
|
|
switch op {
|
|
case TextOperationStartsWith, TextOperationContains, TextOperationEndsWith, TextOperationEqual, TextOperationNotEqual:
|
|
return op
|
|
case TextOperationContainsIgnoreCase:
|
|
return TextOperationContains
|
|
case TextOperationEndsWithIgnoreCase:
|
|
return TextOperationEndsWith
|
|
case TextOperationStartsWithIgnoreCase:
|
|
return TextOperationStartsWith
|
|
case TextOperationEqualIgnoreCase:
|
|
return TextOperationEqual
|
|
case TextOperationNotEqualIgnoreCase:
|
|
return TextOperationNotEqual
|
|
default:
|
|
panic(fmt.Sprintf("unexpected database.TextOperation: %#v", op))
|
|
}
|
|
}
|
|
|
|
func writeTextOperation[T Text](builder *StatementBuilder, col Column, op TextOperation, value any) {
|
|
switch op {
|
|
case TextOperationContains:
|
|
writeOperation[T](builder, col, op.String()+" '%' ||", value)
|
|
builder.WriteString(" || '%'")
|
|
|
|
case TextOperationEndsWith:
|
|
writeOperation[T](builder, col, op.String()+" '%' ||", value)
|
|
|
|
case TextOperationEqual, TextOperationNotEqual:
|
|
writeOperation[T](builder, col, op.String(), value)
|
|
case TextOperationStartsWith:
|
|
writeOperation[T](builder, col, op.String(), value)
|
|
builder.WriteString(" || '%'")
|
|
case TextOperationContainsIgnoreCase, TextOperationEndsWithIgnoreCase, TextOperationStartsWithIgnoreCase, TextOperationEqualIgnoreCase, TextOperationNotEqualIgnoreCase:
|
|
fallthrough
|
|
default:
|
|
panic(fmt.Sprintf("unexpected database.TextOperation: %#v", op))
|
|
}
|
|
}
|
|
|
|
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 (
|
|
// NumberOperationEqual compares two numbers for equality.
|
|
NumberOperationEqual NumberOperation = iota + 1 // =
|
|
// NumberOperationNotEqual compares two numbers for inequality.
|
|
NumberOperationNotEqual // <>
|
|
// NumberOperationLessThan compares two numbers to check if the first is less than the second.
|
|
NumberOperationLessThan // <
|
|
// NumberOperationLessThanOrEqual compares two numbers to check if the first is less than or equal to the second.
|
|
NumberOperationLessThanOrEqual // <=
|
|
// NumberOperationGreaterThan compares two numbers to check if the first is greater than the second.
|
|
NumberOperationGreaterThan // >
|
|
// NumberOperationGreaterThanOrEqual compares two numbers to check if the first is greater than or equal to the second.
|
|
NumberOperationGreaterThanOrEqual // >=
|
|
)
|
|
|
|
func writeNumberOperation[T Number](builder *StatementBuilder, col Column, op NumberOperation, value any) {
|
|
writeOperation[T](builder, col, op.String(), value)
|
|
}
|
|
|
|
type Boolean interface {
|
|
~bool
|
|
}
|
|
|
|
func writeBooleanOperation[T Boolean](builder *StatementBuilder, col Column, value any) {
|
|
writeOperation[T](builder, col, "=", value)
|
|
}
|
|
|
|
type Bytes interface {
|
|
~[]byte
|
|
}
|
|
|
|
// BytesOperation are operations that can be performed on bytea values.
|
|
type BytesOperation uint8
|
|
|
|
const (
|
|
BytesOperationEqual BytesOperation = iota + 1 // =
|
|
BytesOperationNotEqual // <>
|
|
)
|
|
|
|
func writeBytesOperation[T Bytes](builder *StatementBuilder, col Column, op BytesOperation, value any) {
|
|
writeOperation[T](builder, col, op.String(), value)
|
|
}
|
|
|
|
func writeOperation[V Value](builder *StatementBuilder, col Column, op string, value any) {
|
|
if op == "" {
|
|
panic("unsupported operation")
|
|
}
|
|
|
|
switch value.(type) {
|
|
case V, wrappedValue[V], *wrappedValue[V]:
|
|
default:
|
|
panic("unsupported value type")
|
|
}
|
|
col.WriteQualified(builder)
|
|
builder.WriteRune(' ')
|
|
builder.WriteString(op)
|
|
builder.WriteRune(' ')
|
|
builder.WriteArg(value)
|
|
}
|