mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20:57:31 +00:00
perf: query data AS OF SYSTEM TIME
(#5231)
Queries the data in the storage layser at the timestamp when the call hit the API layer
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
@@ -19,14 +20,14 @@ var (
|
||||
testNow = time.Now()
|
||||
)
|
||||
|
||||
//assertPrepare checks if the prepare func executes the correct sql query and returns the correct object
|
||||
//prepareFunc must be of type
|
||||
// assertPrepare checks if the prepare func executes the correct sql query and returns the correct object
|
||||
// prepareFunc must be of type
|
||||
// func() (sq.SelectBuilder, func(*sql.Rows) (*struct, error))
|
||||
// or
|
||||
// func() (sq.SelectBuilder, func(*sql.Row) (*struct, error))
|
||||
//expectedObject represents the return value of scan
|
||||
//sqlExpectation represents the query executed on the database
|
||||
func assertPrepare(t *testing.T, prepareFunc, expectedObject interface{}, sqlExpectation sqlExpectation, isErr checkErr) bool {
|
||||
// expectedObject represents the return value of scan
|
||||
// sqlExpectation represents the query executed on the database
|
||||
func assertPrepare(t *testing.T, prepareFunc, expectedObject interface{}, sqlExpectation sqlExpectation, isErr checkErr, prepareArgs ...reflect.Value) bool {
|
||||
t.Helper()
|
||||
|
||||
client, mock, err := sqlmock.New()
|
||||
@@ -36,7 +37,7 @@ func assertPrepare(t *testing.T, prepareFunc, expectedObject interface{}, sqlExp
|
||||
|
||||
mock = sqlExpectation(mock)
|
||||
|
||||
builder, scan, err := execPrepare(prepareFunc)
|
||||
builder, scan, err := execPrepare(prepareFunc, prepareArgs)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return false
|
||||
@@ -177,12 +178,12 @@ func validateScan(scanType reflect.Type) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func execPrepare(prepare interface{}) (builder sq.SelectBuilder, scan interface{}, err error) {
|
||||
func execPrepare(prepare interface{}, args []reflect.Value) (builder sq.SelectBuilder, scan interface{}, err error) {
|
||||
prepareVal := reflect.ValueOf(prepare)
|
||||
if err := validatePrepare(prepareVal.Type()); err != nil {
|
||||
return sq.SelectBuilder{}, nil, err
|
||||
}
|
||||
res := prepareVal.Call([]reflect.Value{})
|
||||
res := prepareVal.Call(args)
|
||||
|
||||
return res[0].Interface().(sq.SelectBuilder), res[1].Interface(), nil
|
||||
}
|
||||
@@ -191,7 +192,7 @@ func validatePrepare(prepareType reflect.Type) error {
|
||||
if prepareType.Kind() != reflect.Func {
|
||||
return errors.New("prepare is not a function")
|
||||
}
|
||||
if prepareType.NumIn() != 0 {
|
||||
if prepareType.NumIn() < 2 {
|
||||
return fmt.Errorf("prepare: invalid number of inputs: want: 0 got %d", prepareType.NumIn())
|
||||
}
|
||||
if prepareType.NumOut() != 2 {
|
||||
@@ -297,7 +298,7 @@ func TestValidatePrepare(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "correct",
|
||||
t: reflect.TypeOf(func() (sq.SelectBuilder, func(*sql.Rows) (interface{}, error)) {
|
||||
t: reflect.TypeOf(func(context.Context, prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (interface{}, error)) {
|
||||
log.Fatal("should not be executed")
|
||||
return sq.SelectBuilder{}, nil
|
||||
}),
|
||||
@@ -313,3 +314,15 @@ func TestValidatePrepare(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type prepareDB struct{}
|
||||
|
||||
func (_ *prepareDB) Timetravel(time.Duration) string { return " AS OF SYSTEM TIME '-1 ms' " }
|
||||
|
||||
var defaultPrepareArgs = []reflect.Value{reflect.ValueOf(context.Background()), reflect.ValueOf(new(prepareDB))}
|
||||
|
||||
func (*prepareDB) DatabaseName() string { return "db" }
|
||||
|
||||
func (*prepareDB) Username() string { return "user" }
|
||||
|
||||
func (*prepareDB) Type() string { return "type" }
|
||||
|
Reference in New Issue
Block a user