mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-15 04:18:01 +00:00
191 lines
4.2 KiB
Go
191 lines
4.2 KiB
Go
|
package eventstore
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"database/sql"
|
||
|
)
|
||
|
|
||
|
type Pusher interface {
|
||
|
healthier
|
||
|
// Push writes the intents to the storage
|
||
|
// if an intent implements [PushReducerIntent] [PushReducerIntent.Reduce] is called after
|
||
|
// the intent was stored
|
||
|
Push(ctx context.Context, intent *PushIntent) error
|
||
|
}
|
||
|
|
||
|
func NewPushIntent(instance string, opts ...PushOpt) *PushIntent {
|
||
|
intent := &PushIntent{
|
||
|
instance: instance,
|
||
|
}
|
||
|
|
||
|
for _, opt := range opts {
|
||
|
opt(intent)
|
||
|
}
|
||
|
|
||
|
return intent
|
||
|
}
|
||
|
|
||
|
type PushIntent struct {
|
||
|
instance string
|
||
|
reducer Reducer
|
||
|
tx *sql.Tx
|
||
|
aggregates []*PushAggregate
|
||
|
}
|
||
|
|
||
|
func (pi *PushIntent) Instance() string {
|
||
|
return pi.instance
|
||
|
}
|
||
|
|
||
|
func (pi *PushIntent) Reduce(events ...*Event[StoragePayload]) error {
|
||
|
if pi.reducer == nil {
|
||
|
return nil
|
||
|
}
|
||
|
return pi.reducer.Reduce(events...)
|
||
|
}
|
||
|
|
||
|
func (pi *PushIntent) Tx() *sql.Tx {
|
||
|
return pi.tx
|
||
|
}
|
||
|
|
||
|
func (pi *PushIntent) Aggregates() []*PushAggregate {
|
||
|
return pi.aggregates
|
||
|
}
|
||
|
|
||
|
type PushOpt func(pi *PushIntent)
|
||
|
|
||
|
func PushReducer(reducer Reducer) PushOpt {
|
||
|
return func(pi *PushIntent) {
|
||
|
pi.reducer = reducer
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func PushTx(tx *sql.Tx) PushOpt {
|
||
|
return func(pi *PushIntent) {
|
||
|
pi.tx = tx
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func AppendAggregate(owner, typ, id string, opts ...PushAggregateOpt) PushOpt {
|
||
|
return AppendAggregates(NewPushAggregate(owner, typ, id, opts...))
|
||
|
}
|
||
|
|
||
|
func AppendAggregates(aggregates ...*PushAggregate) PushOpt {
|
||
|
return func(pi *PushIntent) {
|
||
|
for _, aggregate := range aggregates {
|
||
|
aggregate.parent = pi
|
||
|
}
|
||
|
pi.aggregates = append(pi.aggregates, aggregates...)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type PushAggregate struct {
|
||
|
parent *PushIntent
|
||
|
// typ of the aggregate
|
||
|
typ string
|
||
|
// id of the aggregate
|
||
|
id string
|
||
|
// owner of the aggregate
|
||
|
owner string
|
||
|
// Commands is an ordered list of changes on the aggregate
|
||
|
commands []Command
|
||
|
// CurrentSequence checks the current state of the aggregate.
|
||
|
// The following types match the current sequence of the aggregate as described:
|
||
|
// * nil or [SequenceIgnore]: Not relevant to add the commands
|
||
|
// * [SequenceMatches]: Must exactly match
|
||
|
// * [SequenceAtLeast]: Must be >= the given sequence
|
||
|
currentSequence CurrentSequence
|
||
|
}
|
||
|
|
||
|
func NewPushAggregate(owner, typ, id string, opts ...PushAggregateOpt) *PushAggregate {
|
||
|
pa := &PushAggregate{
|
||
|
typ: typ,
|
||
|
id: id,
|
||
|
owner: owner,
|
||
|
}
|
||
|
|
||
|
for _, opt := range opts {
|
||
|
opt(pa)
|
||
|
}
|
||
|
|
||
|
return pa
|
||
|
}
|
||
|
|
||
|
func (pa *PushAggregate) Type() string {
|
||
|
return pa.typ
|
||
|
}
|
||
|
|
||
|
func (pa *PushAggregate) ID() string {
|
||
|
return pa.id
|
||
|
}
|
||
|
|
||
|
func (pa *PushAggregate) Owner() string {
|
||
|
return pa.owner
|
||
|
}
|
||
|
|
||
|
func (pa *PushAggregate) Commands() []Command {
|
||
|
return pa.commands
|
||
|
}
|
||
|
|
||
|
func (pa *PushAggregate) Aggregate() *Aggregate {
|
||
|
return &Aggregate{
|
||
|
ID: pa.id,
|
||
|
Type: pa.typ,
|
||
|
Owner: pa.owner,
|
||
|
Instance: pa.parent.instance,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (pa *PushAggregate) CurrentSequence() CurrentSequence {
|
||
|
return pa.currentSequence
|
||
|
}
|
||
|
|
||
|
type PushAggregateOpt func(pa *PushAggregate)
|
||
|
|
||
|
func SetCurrentSequence(currentSequence CurrentSequence) PushAggregateOpt {
|
||
|
return func(pa *PushAggregate) {
|
||
|
pa.currentSequence = currentSequence
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func IgnoreCurrentSequence() PushAggregateOpt {
|
||
|
return func(pa *PushAggregate) {
|
||
|
pa.currentSequence = SequenceIgnore()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func CurrentSequenceMatches(sequence uint32) PushAggregateOpt {
|
||
|
return func(pa *PushAggregate) {
|
||
|
pa.currentSequence = SequenceMatches(sequence)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func CurrentSequenceAtLeast(sequence uint32) PushAggregateOpt {
|
||
|
return func(pa *PushAggregate) {
|
||
|
pa.currentSequence = SequenceAtLeast(sequence)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func AppendCommands(commands ...Command) PushAggregateOpt {
|
||
|
return func(pa *PushAggregate) {
|
||
|
pa.commands = append(pa.commands, commands...)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Command interface {
|
||
|
// Creator is the id of the user which created the action
|
||
|
Creator() string
|
||
|
// Type describes the action it's in the past (e.g. user.created)
|
||
|
Type() string
|
||
|
// Revision of the action
|
||
|
Revision() uint16
|
||
|
// Payload returns the payload of the event. It represent the changed fields by the event
|
||
|
// valid types are:
|
||
|
// * nil: no payload
|
||
|
// * struct: which can be marshalled to json
|
||
|
// * pointer to struct: which can be marshalled to json
|
||
|
// * []byte: json marshalled data
|
||
|
Payload() any
|
||
|
// UniqueConstraints should be added for unique attributes of an event, if nil constraints will not be checked
|
||
|
UniqueConstraints() []*UniqueConstraint
|
||
|
}
|