mirror of
https://github.com/zitadel/zitadel.git
synced 2025-11-16 00:55:01 +00:00
fix: handle multiple statements for a single event in projections (#2313)
* fix: handle multiple statements for a single event in projections * export func type * fix test * Update internal/eventstore/handler/crdb/statement.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/eventstore/handler/crdb/statement.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * change to pointers * add error test case Co-authored-by: Silvan <silvan.reusser@gmail.com>
This commit is contained in:
@@ -11,13 +11,18 @@ import (
|
||||
)
|
||||
|
||||
type wantExecuter struct {
|
||||
query string
|
||||
args []interface{}
|
||||
params []params
|
||||
i int
|
||||
t *testing.T
|
||||
wasExecuted bool
|
||||
shouldExecute bool
|
||||
}
|
||||
|
||||
type params struct {
|
||||
query string
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
var errTestErr = errors.New("some error")
|
||||
|
||||
func (ex *wantExecuter) check(t *testing.T) {
|
||||
@@ -34,12 +39,18 @@ func (ex *wantExecuter) check(t *testing.T) {
|
||||
func (ex *wantExecuter) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
ex.t.Helper()
|
||||
ex.wasExecuted = true
|
||||
if query != ex.query {
|
||||
ex.t.Errorf("wrong query:\n expected:\n %q\n got:\n %q", ex.query, query)
|
||||
if ex.i >= len(ex.params) {
|
||||
ex.t.Errorf("did not expect more exec, but got:\n %q with %q", query, args)
|
||||
return nil, nil
|
||||
}
|
||||
if !reflect.DeepEqual(ex.args, args) {
|
||||
ex.t.Errorf("wrong args:\n expected:\n %v\n got:\n %v", ex.args, args)
|
||||
p := ex.params[ex.i]
|
||||
if query != p.query {
|
||||
ex.t.Errorf("wrong query:\n expected:\n %q\n got:\n %q", p.query, query)
|
||||
}
|
||||
if !reflect.DeepEqual(p.args, args) {
|
||||
ex.t.Errorf("wrong args:\n expected:\n %v\n got:\n %v", p.args, args)
|
||||
}
|
||||
ex.i++
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -137,9 +148,13 @@ func TestNewCreateStatement(t *testing.T) {
|
||||
sequence: 1,
|
||||
previousSequence: 1,
|
||||
executer: &wantExecuter{
|
||||
query: "INSERT INTO my_table (col1) VALUES ($1)",
|
||||
params: []params{
|
||||
{
|
||||
query: "INSERT INTO my_table (col1) VALUES ($1)",
|
||||
args: []interface{}{"val"},
|
||||
},
|
||||
},
|
||||
shouldExecute: true,
|
||||
args: []interface{}{"val"},
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return err == nil
|
||||
@@ -255,9 +270,13 @@ func TestNewUpsertStatement(t *testing.T) {
|
||||
sequence: 1,
|
||||
previousSequence: 1,
|
||||
executer: &wantExecuter{
|
||||
query: "UPSERT INTO my_table (col1) VALUES ($1)",
|
||||
params: []params{
|
||||
{
|
||||
query: "UPSERT INTO my_table (col1) VALUES ($1)",
|
||||
args: []interface{}{"val"},
|
||||
},
|
||||
},
|
||||
shouldExecute: true,
|
||||
args: []interface{}{"val"},
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return err == nil
|
||||
@@ -422,9 +441,13 @@ func TestNewUpdateStatement(t *testing.T) {
|
||||
sequence: 1,
|
||||
previousSequence: 1,
|
||||
executer: &wantExecuter{
|
||||
query: "UPDATE my_table SET (col1) = ($1) WHERE (col2 = $2)",
|
||||
params: []params{
|
||||
{
|
||||
query: "UPDATE my_table SET (col1) = ($1) WHERE (col2 = $2)",
|
||||
args: []interface{}{"val", 1},
|
||||
},
|
||||
},
|
||||
shouldExecute: true,
|
||||
args: []interface{}{"val", 1},
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return err == nil
|
||||
@@ -541,9 +564,13 @@ func TestNewDeleteStatement(t *testing.T) {
|
||||
sequence: 1,
|
||||
previousSequence: 1,
|
||||
executer: &wantExecuter{
|
||||
query: "DELETE FROM my_table WHERE (col1 = $1)",
|
||||
params: []params{
|
||||
{
|
||||
query: "DELETE FROM my_table WHERE (col1 = $1)",
|
||||
args: []interface{}{1},
|
||||
},
|
||||
},
|
||||
shouldExecute: true,
|
||||
args: []interface{}{1},
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return err == nil
|
||||
@@ -572,7 +599,7 @@ func TestNewNoOpStatement(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want handler.Statement
|
||||
want *handler.Statement
|
||||
}{
|
||||
{
|
||||
name: "generate correctly",
|
||||
@@ -583,7 +610,7 @@ func TestNewNoOpStatement(t *testing.T) {
|
||||
previousSequence: 3,
|
||||
},
|
||||
},
|
||||
want: handler.Statement{
|
||||
want: &handler.Statement{
|
||||
AggregateType: "agg",
|
||||
Execute: nil,
|
||||
Sequence: 5,
|
||||
@@ -600,6 +627,174 @@ func TestNewNoOpStatement(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewMultiStatement(t *testing.T) {
|
||||
type args struct {
|
||||
table string
|
||||
event *testEvent
|
||||
execs []func(eventstore.EventReader) Exec
|
||||
}
|
||||
|
||||
type want struct {
|
||||
table string
|
||||
aggregateType eventstore.AggregateType
|
||||
sequence uint64
|
||||
previousSequence uint64
|
||||
executer *wantExecuter
|
||||
isErr func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "no op",
|
||||
args: args{
|
||||
table: "my_table",
|
||||
event: &testEvent{
|
||||
aggregateType: "agg",
|
||||
sequence: 1,
|
||||
previousSequence: 0,
|
||||
},
|
||||
execs: nil,
|
||||
},
|
||||
want: want{
|
||||
executer: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no condition",
|
||||
args: args{
|
||||
table: "my_table",
|
||||
event: &testEvent{
|
||||
aggregateType: "agg",
|
||||
sequence: 1,
|
||||
previousSequence: 0,
|
||||
},
|
||||
execs: []func(eventstore.EventReader) Exec{
|
||||
AddDeleteStatement(
|
||||
[]handler.Condition{},
|
||||
),
|
||||
AddCreateStatement(
|
||||
[]handler.Column{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: 1,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
table: "my_table",
|
||||
aggregateType: "agg",
|
||||
sequence: 1,
|
||||
previousSequence: 1,
|
||||
executer: &wantExecuter{
|
||||
shouldExecute: false,
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return errors.Is(err, handler.ErrNoCondition)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "correct",
|
||||
args: args{
|
||||
table: "my_table",
|
||||
event: &testEvent{
|
||||
sequence: 1,
|
||||
previousSequence: 0,
|
||||
aggregateType: "agg",
|
||||
},
|
||||
execs: []func(eventstore.EventReader) Exec{
|
||||
AddDeleteStatement(
|
||||
[]handler.Condition{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: 1,
|
||||
},
|
||||
}),
|
||||
AddCreateStatement(
|
||||
[]handler.Column{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: 1,
|
||||
},
|
||||
}),
|
||||
AddUpsertStatement(
|
||||
[]handler.Column{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: 1,
|
||||
},
|
||||
}),
|
||||
AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: 1,
|
||||
},
|
||||
},
|
||||
[]handler.Condition{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: 1,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
table: "my_table",
|
||||
aggregateType: "agg",
|
||||
sequence: 1,
|
||||
previousSequence: 1,
|
||||
executer: &wantExecuter{
|
||||
params: []params{
|
||||
{
|
||||
query: "DELETE FROM my_table WHERE (col1 = $1)",
|
||||
args: []interface{}{1},
|
||||
},
|
||||
{
|
||||
query: "INSERT INTO my_table (col1) VALUES ($1)",
|
||||
args: []interface{}{1},
|
||||
},
|
||||
{
|
||||
query: "UPSERT INTO my_table (col1) VALUES ($1)",
|
||||
args: []interface{}{1},
|
||||
},
|
||||
{
|
||||
query: "UPDATE my_table SET (col1) = ($1) WHERE (col1 = $2)",
|
||||
args: []interface{}{1, 1},
|
||||
},
|
||||
},
|
||||
shouldExecute: true,
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return err == nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
stmt := NewMultiStatement(tt.args.event, tt.args.execs...)
|
||||
|
||||
if tt.want.executer != nil && stmt.Execute == nil {
|
||||
t.Error("expected executer, but was nil")
|
||||
}
|
||||
if stmt.Execute == nil {
|
||||
return
|
||||
}
|
||||
tt.want.executer.t = t
|
||||
err := stmt.Execute(tt.want.executer, tt.args.table)
|
||||
if !tt.want.isErr(err) {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
tt.want.executer.check(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatement_Execute(t *testing.T) {
|
||||
type fields struct {
|
||||
execute func(ex handler.Executer, projectionName string) error
|
||||
|
||||
Reference in New Issue
Block a user