mirror of
https://github.com/zitadel/zitadel
synced 2024-11-22 00:39:36 +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:
parent
80003939ad
commit
e38abdcdf3
@ -93,102 +93,4 @@ protoc \
|
||||
mv ${ZITADEL_PATH}/pkg/grpc/auth/zitadel/* ${ZITADEL_PATH}/pkg/grpc/auth
|
||||
rm -r ${ZITADEL_PATH}/pkg/grpc/auth/zitadel
|
||||
|
||||
## generate docs
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,system.md \
|
||||
${PROTO_PATH}/system.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,auth.md \
|
||||
${PROTO_PATH}/auth.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,management.md \
|
||||
${PROTO_PATH}/management.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,admin.md \
|
||||
${PROTO_PATH}/admin.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,action.md \
|
||||
${PROTO_PATH}/action.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,app.md \
|
||||
${PROTO_PATH}/app.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,auth_n_key.md \
|
||||
${PROTO_PATH}/auth_n_key.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,change.md \
|
||||
${PROTO_PATH}/change.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,event.md \
|
||||
${PROTO_PATH}/event.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,idp.md \
|
||||
${PROTO_PATH}/idp.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,instance.md \
|
||||
${PROTO_PATH}/instance.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,member.md \
|
||||
${PROTO_PATH}/member.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,message.md \
|
||||
${PROTO_PATH}/message.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,metadata.md \
|
||||
${PROTO_PATH}/metadata.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,object.md \
|
||||
${PROTO_PATH}/object.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,options.md \
|
||||
${PROTO_PATH}/options.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,org.md \
|
||||
${PROTO_PATH}/org.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,policy.md \
|
||||
${PROTO_PATH}/policy.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,project.md \
|
||||
${PROTO_PATH}/project.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,settings.md \
|
||||
${PROTO_PATH}/settings.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,text.md \
|
||||
${PROTO_PATH}/text.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,user.md \
|
||||
${PROTO_PATH}/user.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,settings.md \
|
||||
${PROTO_PATH}/settings.proto
|
||||
protoc \
|
||||
-I=/proto/include \
|
||||
--doc_out=${DOCS_PATH} --doc_opt=${PROTO_PATH}/docs/zitadel-md.tmpl,v1.md \
|
||||
${PROTO_PATH}/v1.proto
|
||||
|
||||
echo "done generating grpc"
|
||||
|
@ -59,8 +59,8 @@ The user provided by flags needs privileges to
|
||||
func InitAll(config *Config) {
|
||||
err := initialise(config.Database,
|
||||
VerifyUser(config.Database.Username(), config.Database.Password()),
|
||||
VerifyDatabase(config.Database.Database()),
|
||||
VerifyGrant(config.Database.Database(), config.Database.Username()),
|
||||
VerifyDatabase(config.Database.DatabaseName()),
|
||||
VerifyGrant(config.Database.DatabaseName(), config.Database.Username()),
|
||||
)
|
||||
logging.OnError(err).Fatal("unable to initialize the database")
|
||||
|
||||
@ -82,7 +82,7 @@ func initialise(config database.Config, steps ...func(*sql.DB) error) error {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
return Init(db, steps...)
|
||||
return Init(db.DB, steps...)
|
||||
}
|
||||
|
||||
func Init(db *sql.DB, steps ...func(*sql.DB) error) error {
|
||||
|
@ -27,7 +27,7 @@ The user provided by flags needs priviledge to
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
config := MustNewConfig(viper.GetViper())
|
||||
|
||||
err := initialise(config.Database, VerifyDatabase(config.Database.Database()))
|
||||
err := initialise(config.Database, VerifyDatabase(config.Database.DatabaseName()))
|
||||
logging.OnError(err).Fatal("unable to initialize the database")
|
||||
},
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ Prereqesits:
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
config := MustNewConfig(viper.GetViper())
|
||||
|
||||
err := initialise(config.Database, VerifyGrant(config.Database.Database(), config.Database.Username()))
|
||||
err := initialise(config.Database, VerifyGrant(config.Database.DatabaseName(), config.Database.Username()))
|
||||
logging.OnError(err).Fatal("unable to set grant")
|
||||
},
|
||||
}
|
||||
|
@ -66,14 +66,14 @@ func VerifyZitadel(db *sql.DB, config database.Config) error {
|
||||
}
|
||||
|
||||
func verifyZitadel(config database.Config) error {
|
||||
logging.WithFields("database", config.Database()).Info("verify zitadel")
|
||||
logging.WithFields("database", config.DatabaseName()).Info("verify zitadel")
|
||||
|
||||
db, err := database.Connect(config, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := VerifyZitadel(db, config); err != nil {
|
||||
if err := VerifyZitadel(db.DB, config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -128,5 +128,5 @@ func keyStorage(config database.Config, masterKey string) (crypto.KeyStorage, er
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cryptoDB.NewKeyStorage(db, masterKey)
|
||||
return cryptoDB.NewKeyStorage(db.DB, masterKey)
|
||||
}
|
||||
|
@ -66,14 +66,14 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
logging.OnError(err).Fatal("unable to start eventstore")
|
||||
migration.RegisterMappers(eventstoreClient)
|
||||
|
||||
steps.s1ProjectionTable = &ProjectionTable{dbClient: dbClient}
|
||||
steps.s2AssetsTable = &AssetTable{dbClient: dbClient}
|
||||
steps.s1ProjectionTable = &ProjectionTable{dbClient: dbClient.DB}
|
||||
steps.s2AssetsTable = &AssetTable{dbClient: dbClient.DB}
|
||||
|
||||
steps.FirstInstance.instanceSetup = config.DefaultInstance
|
||||
steps.FirstInstance.userEncryptionKey = config.EncryptionKeys.User
|
||||
steps.FirstInstance.smtpEncryptionKey = config.EncryptionKeys.SMTP
|
||||
steps.FirstInstance.masterKey = masterKey
|
||||
steps.FirstInstance.db = dbClient
|
||||
steps.FirstInstance.db = dbClient.DB
|
||||
steps.FirstInstance.es = eventstoreClient
|
||||
steps.FirstInstance.defaults = config.SystemDefaults
|
||||
steps.FirstInstance.zitadelRoles = config.InternalAuthZ.RolePermissionMappings
|
||||
@ -81,11 +81,11 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
||||
steps.FirstInstance.externalSecure = config.ExternalSecure
|
||||
steps.FirstInstance.externalPort = config.ExternalPort
|
||||
|
||||
steps.s4EventstoreIndexes = &EventstoreIndexes{dbClient: dbClient, dbType: config.Database.Type()}
|
||||
steps.s5LastFailed = &LastFailed{dbClient: dbClient}
|
||||
steps.s6OwnerRemoveColumns = &OwnerRemoveColumns{dbClient: dbClient}
|
||||
steps.s7LogstoreTables = &LogstoreTables{dbClient: dbClient, username: config.Database.Username(), dbType: config.Database.Type()}
|
||||
steps.s8AuthTokens = &AuthTokenIndexes{dbClient: dbClient}
|
||||
steps.s4EventstoreIndexes = &EventstoreIndexes{dbClient: dbClient.DB, dbType: config.Database.Type()}
|
||||
steps.s5LastFailed = &LastFailed{dbClient: dbClient.DB}
|
||||
steps.s6OwnerRemoveColumns = &OwnerRemoveColumns{dbClient: dbClient.DB}
|
||||
steps.s7LogstoreTables = &LogstoreTables{dbClient: dbClient.DB, username: config.Database.Username(), dbType: config.Database.Type()}
|
||||
steps.s8AuthTokens = &AuthTokenIndexes{dbClient: dbClient.DB}
|
||||
|
||||
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil)
|
||||
logging.OnError(err).Fatal("unable to start projections")
|
||||
|
@ -3,7 +3,6 @@ package start
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"net"
|
||||
@ -95,7 +94,7 @@ func startZitadel(config *Config, masterKey string) error {
|
||||
return fmt.Errorf("cannot start client for projection: %w", err)
|
||||
}
|
||||
|
||||
keyStorage, err := cryptoDB.NewKeyStorage(dbClient, masterKey)
|
||||
keyStorage, err := cryptoDB.NewKeyStorage(dbClient.DB, masterKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot start key storage: %w", err)
|
||||
}
|
||||
@ -120,7 +119,7 @@ func startZitadel(config *Config, masterKey string) error {
|
||||
return fmt.Errorf("error starting authz repo: %w", err)
|
||||
}
|
||||
|
||||
storage, err := config.AssetStorage.NewStorage(dbClient)
|
||||
storage, err := config.AssetStorage.NewStorage(dbClient.DB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot start asset storage client: %w", err)
|
||||
}
|
||||
@ -162,7 +161,7 @@ func startZitadel(config *Config, masterKey string) error {
|
||||
}
|
||||
|
||||
usageReporter := logstore.UsageReporterFunc(commands.ReportUsage)
|
||||
actionsLogstoreSvc := logstore.New(commands, usageReporter, actionsExecutionDBEmitter, actionsExecutionStdoutEmitter)
|
||||
actionsLogstoreSvc := logstore.New(queries, usageReporter, actionsExecutionDBEmitter, actionsExecutionStdoutEmitter)
|
||||
if actionsLogstoreSvc.Enabled() {
|
||||
logging.Warn("execution logs are currently in beta")
|
||||
}
|
||||
@ -175,7 +174,7 @@ func startZitadel(config *Config, masterKey string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = startAPIs(ctx, clock, router, commands, queries, eventstoreClient, dbClient, config, storage, authZRepo, keys, commands, usageReporter)
|
||||
err = startAPIs(ctx, clock, router, commands, queries, eventstoreClient, dbClient, config, storage, authZRepo, keys, queries, usageReporter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -189,7 +188,7 @@ func startAPIs(
|
||||
commands *command.Commands,
|
||||
queries *query.Queries,
|
||||
eventstore *eventstore.Eventstore,
|
||||
dbClient *sql.DB,
|
||||
dbClient *database.DB,
|
||||
config *Config,
|
||||
store static.Storage,
|
||||
authZRepo authz_repo.Repository,
|
||||
@ -233,10 +232,10 @@ func startAPIs(
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting admin repo: %w", err)
|
||||
}
|
||||
if err := apis.RegisterServer(ctx, system.CreateServer(commands, queries, adminRepo, config.Database.Database(), config.DefaultInstance, config.ExternalDomain)); err != nil {
|
||||
if err := apis.RegisterServer(ctx, system.CreateServer(commands, queries, adminRepo, config.Database.DatabaseName(), config.DefaultInstance, config.ExternalDomain)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.Database(), commands, queries, config.SystemDefaults, adminRepo, config.ExternalSecure, keys.User)); err != nil {
|
||||
if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.DatabaseName(), commands, queries, config.SystemDefaults, adminRepo, config.ExternalSecure, keys.User)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, keys.User, config.ExternalSecure, config.AuditLogRetention)); err != nil {
|
||||
@ -247,7 +246,7 @@ func startAPIs(
|
||||
}
|
||||
instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader, login.IgnoreInstanceEndpoints...)
|
||||
assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge)
|
||||
apis.RegisterHandler(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, instanceInterceptor.Handler, assetsCache.Handler, accessInterceptor.Handle))
|
||||
apis.RegisterHandler(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, accessInterceptor.Handle))
|
||||
|
||||
userAgentInterceptor, err := middleware.NewUserAgentHandler(config.UserAgentCookie, keys.UserAgentCookieKey, id.SonyFlakeGenerator(), config.ExternalSecure, login.EndpointResources)
|
||||
if err != nil {
|
||||
@ -272,7 +271,7 @@ func startAPIs(
|
||||
}
|
||||
apis.RegisterHandler(saml.HandlerPrefix, samlProvider.HttpHandler())
|
||||
|
||||
c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, instanceInterceptor.Handler, accessInterceptor.Handle, config.CustomerPortal)
|
||||
c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, middleware.CallDurationHandler, instanceInterceptor.Handler, accessInterceptor.Handle, config.CustomerPortal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to start console: %w", err)
|
||||
}
|
||||
|
173
go.mod
173
go.mod
@ -3,22 +3,22 @@ module github.com/zitadel/zitadel
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.28.1
|
||||
github.com/BurntSushi/toml v0.4.1
|
||||
cloud.google.com/go/storage v1.29.0
|
||||
github.com/BurntSushi/toml v1.2.1
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.0.0
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.11.2
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible
|
||||
github.com/Masterminds/squirrel v1.5.2
|
||||
github.com/VictoriaMetrics/fastcache v1.8.0
|
||||
github.com/Masterminds/squirrel v1.5.3
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1
|
||||
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b
|
||||
github.com/allegro/bigcache v1.2.1
|
||||
github.com/benbjohnson/clock v1.2.0
|
||||
github.com/benbjohnson/clock v1.3.0
|
||||
github.com/boombuler/barcode v1.0.1
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.18
|
||||
github.com/dop251/goja v0.0.0-20220815083517-0c74f9139fd6
|
||||
github.com/dop251/goja_nodejs v0.0.0-20220905124449-678b33ca5009
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.20
|
||||
github.com/dop251/goja v0.0.0-20230216180835-5937a312edda
|
||||
github.com/dop251/goja_nodejs v0.0.0-20230207183254-2229640ea097
|
||||
github.com/drone/envsubst v1.0.3
|
||||
github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a
|
||||
github.com/duo-labs/webauthn v0.0.0-20221205164246-ebaf9b74c6ec
|
||||
github.com/envoyproxy/protoc-gen-validate v0.9.1
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/golang/glog v1.0.0
|
||||
@ -33,26 +33,26 @@ require (
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.1
|
||||
github.com/h2non/gock v1.2.0
|
||||
github.com/improbable-eng/grpc-web v0.15.0
|
||||
github.com/jackc/pgconn v1.12.1
|
||||
github.com/jackc/pgtype v1.11.0
|
||||
github.com/jackc/pgx/v4 v4.16.1
|
||||
github.com/jackc/pgconn v1.14.0
|
||||
github.com/jackc/pgtype v1.14.0
|
||||
github.com/jackc/pgx/v4 v4.18.0
|
||||
github.com/jarcoal/jpath v0.0.0-20140328210829-f76b8b2dbf52
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/k3a/html2text v1.0.8
|
||||
github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73
|
||||
github.com/lib/pq v1.10.6
|
||||
github.com/k3a/html2text v1.1.0
|
||||
github.com/kevinburke/twilio-go v0.0.0-20221122012537-65f3dd7539e2
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0
|
||||
github.com/minio/minio-go/v7 v7.0.20
|
||||
github.com/mitchellh/mapstructure v1.4.3
|
||||
github.com/muesli/gamut v0.2.0
|
||||
github.com/nicksnyder/go-i18n/v2 v2.1.2
|
||||
github.com/minio/minio-go/v7 v7.0.49
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/muesli/gamut v0.3.1
|
||||
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/otp v1.3.0
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/rakyll/statik v0.1.7
|
||||
github.com/rs/cors v1.8.3
|
||||
github.com/sony/sonyflake v1.0.0
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/sony/sonyflake v1.1.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/viper v1.15.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
|
||||
github.com/ttacon/libphonenumber v1.2.1
|
||||
@ -61,21 +61,21 @@ require (
|
||||
github.com/zitadel/saml v0.0.10
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.27.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0
|
||||
go.opentelemetry.io/otel v1.2.0
|
||||
go.opentelemetry.io/otel v1.11.2
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.25.0
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0
|
||||
go.opentelemetry.io/otel/metric v0.25.0
|
||||
go.opentelemetry.io/otel/sdk v1.2.0
|
||||
go.opentelemetry.io/otel/sdk v1.11.2
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.25.0
|
||||
go.opentelemetry.io/otel/sdk/metric v0.25.0
|
||||
go.opentelemetry.io/otel/trace v1.2.0
|
||||
go.opentelemetry.io/otel/trace v1.11.2
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/net v0.7.0
|
||||
golang.org/x/oauth2 v0.5.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/text v0.7.0
|
||||
golang.org/x/tools v0.3.0
|
||||
golang.org/x/tools v0.6.0
|
||||
google.golang.org/api v0.110.0
|
||||
google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148
|
||||
google.golang.org/grpc v1.53.0
|
||||
@ -85,119 +85,120 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.108.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.35.2 // indirect
|
||||
github.com/cloudflare/cfssl v1.6.3 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.0 // indirect
|
||||
cloud.google.com/go/compute v1.18.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v0.11.0 // indirect
|
||||
cloud.google.com/go/trace v1.4.0 // indirect
|
||||
cloud.google.com/go/iam v0.12.0 // indirect
|
||||
cloud.google.com/go/trace v1.8.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/amdonov/xmlsig v0.1.0 // indirect
|
||||
github.com/beevik/etree v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
|
||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
||||
github.com/dsoprea/go-exif v0.0.0-20210131231135-d154f10435cc // indirect
|
||||
github.com/dsoprea/go-exif/v2 v2.0.0-20200604193436-ca8584a0e1c4 // indirect
|
||||
github.com/dsoprea/go-iptc v0.0.0-20200609062250-162ae6b44feb // indirect
|
||||
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20210128210355-86b1014917f2 // indirect
|
||||
github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d // indirect
|
||||
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200609050348-3db9b63b202c // indirect
|
||||
github.com/dsoprea/go-png-image-structure v0.0.0-20200807080309-a98d4e94ac82 // indirect
|
||||
github.com/dsoprea/go-utility v0.0.0-20200512094054-1abbbc781176 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.2.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.8.1 // indirect
|
||||
github.com/dsoprea/go-exif v0.0.0-20221012082141-d21ac8e2de85 // indirect
|
||||
github.com/dsoprea/go-exif/v2 v2.0.0-20221012082141-d21ac8e2de85 // indirect
|
||||
github.com/dsoprea/go-iptc v0.0.0-20200610044640-bc9ca208b413 // indirect
|
||||
github.com/dsoprea/go-jpeg-image-structure v0.0.0-20221012074422-4f3f7e934102 // indirect
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/dsoprea/go-photoshop-info-format v0.0.0-20200610045659-121dd752914d // indirect
|
||||
github.com/dsoprea/go-png-image-structure v0.0.0-20210512210324-29b889a6093d // indirect
|
||||
github.com/dsoprea/go-utility v0.0.0-20221003172846-a3e1774ef349 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||
github.com/go-errors/errors v1.0.2 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
|
||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/certificate-transparency-go v1.0.21 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.4 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/h2non/filetype v1.1.1 // indirect
|
||||
github.com/h2non/filetype v1.1.3 // indirect
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.2 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/jonboulle/clockwork v0.3.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7 // indirect
|
||||
github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c // indirect
|
||||
github.com/klauspost/compress v1.14.2 // indirect
|
||||
github.com/klauspost/cpuid v1.3.1 // indirect
|
||||
github.com/kevinburke/rest v0.0.0-20230118171807-ac09c3f0ec45 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/minio/md5-simd v1.1.0 // indirect
|
||||
github.com/minio/sha256-simd v0.1.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 // indirect
|
||||
github.com/muesli/kmeans v0.2.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/muesli/kmeans v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_golang v1.13.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/rs/xid v1.2.1 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/rs/xid v1.4.0 // indirect
|
||||
github.com/russellhaering/goxmldsig v1.2.0 // indirect
|
||||
github.com/satori/go.uuid v1.2.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/afero v1.9.2 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect
|
||||
go.opentelemetry.io/otel/internal/metric v0.25.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.15.0 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
nhooyr.io/websocket v1.8.7 // indirect
|
||||
)
|
||||
|
||||
replace github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.4
|
||||
|
||||
|
@ -2,11 +2,11 @@ package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/admin/repository/eventsourcing/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/admin/repository/eventsourcing/spooler"
|
||||
admin_view "github.com/zitadel/zitadel/internal/admin/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
eventstore2 "github.com/zitadel/zitadel/internal/eventstore"
|
||||
v1 "github.com/zitadel/zitadel/internal/eventstore/v1"
|
||||
es_spol "github.com/zitadel/zitadel/internal/eventstore/v1/spooler"
|
||||
@ -23,7 +23,7 @@ type EsRepository struct {
|
||||
eventstore.AdministratorRepo
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, conf Config, static static.Storage, dbClient *sql.DB, esV2 *eventstore2.Eventstore) (*EsRepository, error) {
|
||||
func Start(ctx context.Context, conf Config, static static.Storage, dbClient *database.DB, esV2 *eventstore2.Eventstore) (*EsRepository, error) {
|
||||
es, err := v1.Start(dbClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -2,10 +2,10 @@ package spooler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/admin/repository/eventsourcing/handler"
|
||||
"github.com/zitadel/zitadel/internal/admin/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
v1 "github.com/zitadel/zitadel/internal/eventstore/v1"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/spooler"
|
||||
@ -20,11 +20,11 @@ type SpoolerConfig struct {
|
||||
Handlers handler.Configs
|
||||
}
|
||||
|
||||
func StartSpooler(ctx context.Context, c SpoolerConfig, es v1.Eventstore, esV2 *eventstore.Eventstore, view *view.View, sql *sql.DB, static static.Storage) *spooler.Spooler {
|
||||
func StartSpooler(ctx context.Context, c SpoolerConfig, es v1.Eventstore, esV2 *eventstore.Eventstore, view *view.View, sql *database.DB, static static.Storage) *spooler.Spooler {
|
||||
spoolerConfig := spooler.Config{
|
||||
Eventstore: es,
|
||||
EventstoreV2: esV2,
|
||||
Locker: &locker{dbClient: sql},
|
||||
Locker: &locker{dbClient: sql.DB},
|
||||
ConcurrentWorkers: c.ConcurrentWorkers,
|
||||
ConcurrentInstances: c.ConcurrentInstances,
|
||||
ViewHandlers: handler.Register(ctx, c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, static),
|
||||
|
@ -1,16 +1,15 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
)
|
||||
|
||||
type View struct {
|
||||
Db *gorm.DB
|
||||
}
|
||||
|
||||
func StartView(sqlClient *sql.DB) (*View, error) {
|
||||
func StartView(sqlClient *database.DB) (*View, error) {
|
||||
gorm, err := gorm.Open("postgres", sqlClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -82,7 +82,7 @@ func DefaultErrorHandler(w http.ResponseWriter, r *http.Request, err error, code
|
||||
http.Error(w, err.Error(), code)
|
||||
}
|
||||
|
||||
func NewHandler(commands *command.Commands, verifier *authz.TokenVerifier, authConfig authz.Config, idGenerator id.Generator, storage static.Storage, queries *query.Queries, instanceInterceptor, assetCacheInterceptor, accessInterceptor func(handler http.Handler) http.Handler) http.Handler {
|
||||
func NewHandler(commands *command.Commands, verifier *authz.TokenVerifier, authConfig authz.Config, idGenerator id.Generator, storage static.Storage, queries *query.Queries, callDurationInterceptor, instanceInterceptor, assetCacheInterceptor, accessInterceptor func(handler http.Handler) http.Handler) http.Handler {
|
||||
h := &Handler{
|
||||
commands: commands,
|
||||
errorHandler: DefaultErrorHandler,
|
||||
@ -94,7 +94,7 @@ func NewHandler(commands *command.Commands, verifier *authz.TokenVerifier, authC
|
||||
|
||||
verifier.RegisterServer("Assets-API", "assets", AssetsService_AuthMethods)
|
||||
router := mux.NewRouter()
|
||||
router.Use(instanceInterceptor, assetCacheInterceptor, accessInterceptor)
|
||||
router.Use(callDurationInterceptor, instanceInterceptor, assetCacheInterceptor, accessInterceptor)
|
||||
RegisterRoutes(router, h)
|
||||
router.PathPrefix("/{owner}").Methods("GET").HandlerFunc(DownloadHandleFunc(h, h.GetFile()))
|
||||
return http_util.CopyHeadersToContext(http_mw.CORSInterceptor(router))
|
||||
|
17
internal/api/authz/detach.go
Normal file
17
internal/api/authz/detach.go
Normal file
@ -0,0 +1,17 @@
|
||||
package authz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Detach(ctx context.Context) context.Context { return detachedContext{ctx} }
|
||||
|
||||
type detachedContext struct {
|
||||
parent context.Context
|
||||
}
|
||||
|
||||
func (v detachedContext) Deadline() (time.Time, bool) { return time.Time{}, false }
|
||||
func (v detachedContext) Done() <-chan struct{} { return nil }
|
||||
func (v detachedContext) Err() error { return nil }
|
||||
func (v detachedContext) Value(key interface{}) interface{} { return v.parent.Value(key) }
|
38
internal/api/call/duration.go
Normal file
38
internal/api/call/duration.go
Normal file
@ -0,0 +1,38 @@
|
||||
package call
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type durationKey struct{}
|
||||
|
||||
var key *durationKey = (*durationKey)(nil)
|
||||
|
||||
// WithTimestamp sets [time.Now()] adds the call field to the context
|
||||
// if it's not already set
|
||||
func WithTimestamp(parent context.Context) context.Context {
|
||||
if parent.Value(key) != nil {
|
||||
return parent
|
||||
}
|
||||
return context.WithValue(parent, key, time.Now())
|
||||
}
|
||||
|
||||
// FromContext returns the [time.Time] the call hit the api
|
||||
func FromContext(ctx context.Context) (t time.Time) {
|
||||
value := ctx.Value(key)
|
||||
if t, ok := value.(time.Time); ok {
|
||||
return t
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// Took returns the time the call took so far
|
||||
func Took(ctx context.Context) time.Duration {
|
||||
start := FromContext(ctx)
|
||||
if start.IsZero() {
|
||||
return 0
|
||||
}
|
||||
return time.Since(start)
|
||||
}
|
119
internal/api/call/duration_test.go
Normal file
119
internal/api/call/duration_test.go
Normal file
@ -0,0 +1,119 @@
|
||||
package call
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTook(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
startIsZero bool
|
||||
}{
|
||||
{
|
||||
name: "no start",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
},
|
||||
startIsZero: true,
|
||||
},
|
||||
{
|
||||
name: "with start",
|
||||
args: args{
|
||||
ctx: WithTimestamp(context.Background()),
|
||||
},
|
||||
startIsZero: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Took(tt.args.ctx)
|
||||
if tt.startIsZero && got != 0 {
|
||||
t.Errorf("Duration should be 0 but was %v", got)
|
||||
}
|
||||
if !tt.startIsZero && got <= 0 {
|
||||
t.Errorf("Duration should be greater 0 but was %d", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromContext(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
isZero bool
|
||||
}{
|
||||
{
|
||||
name: "no start",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
},
|
||||
isZero: true,
|
||||
},
|
||||
{
|
||||
name: "with start",
|
||||
args: args{
|
||||
ctx: WithTimestamp(context.Background()),
|
||||
},
|
||||
isZero: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := FromContext(tt.args.ctx)
|
||||
if tt.isZero != got.IsZero() {
|
||||
t.Errorf("Time is zero should be %v but was %v", tt.isZero, got.IsZero())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithTimestamp(t *testing.T) {
|
||||
start := time.Date(2019, 4, 29, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
noPrevious bool
|
||||
}{
|
||||
{
|
||||
name: "fresh context",
|
||||
args: args{
|
||||
ctx: context.WithValue(context.Background(), key, start),
|
||||
},
|
||||
noPrevious: true,
|
||||
},
|
||||
{
|
||||
name: "with start",
|
||||
args: args{
|
||||
ctx: WithTimestamp(context.Background()),
|
||||
},
|
||||
noPrevious: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := WithTimestamp(tt.args.ctx)
|
||||
val := got.Value(key).(time.Time)
|
||||
|
||||
if !tt.noPrevious && val.Before(start) {
|
||||
t.Errorf("time should be now not %v", val)
|
||||
}
|
||||
if tt.noPrevious && val.After(start) {
|
||||
t.Errorf("time should be start not %v", val)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -88,17 +88,6 @@ func (c *count) getProgress() string {
|
||||
"project_grant_members " + strconv.Itoa(c.projectGrantMemberCount) + "/" + strconv.Itoa(c.projectGrantMemberLen)
|
||||
}
|
||||
|
||||
func Detach(ctx context.Context) context.Context { return detachedContext{ctx} }
|
||||
|
||||
type detachedContext struct {
|
||||
parent context.Context
|
||||
}
|
||||
|
||||
func (v detachedContext) Deadline() (time.Time, bool) { return time.Time{}, false }
|
||||
func (v detachedContext) Done() <-chan struct{} { return nil }
|
||||
func (v detachedContext) Err() error { return nil }
|
||||
func (v detachedContext) Value(key interface{}) interface{} { return v.parent.Value(key) }
|
||||
|
||||
func (s *Server) ImportData(ctx context.Context, req *admin_pb.ImportDataRequest) (_ *admin_pb.ImportDataResponse, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@ -169,7 +158,7 @@ func (s *Server) ImportData(ctx context.Context, req *admin_pb.ImportDataRequest
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dctx := Detach(ctx)
|
||||
dctx := authz.Detach(ctx)
|
||||
go func() {
|
||||
ch := make(chan importResponse, 1)
|
||||
ctxTimeout, cancel := context.WithTimeout(dctx, timeoutDuration)
|
||||
|
@ -71,6 +71,7 @@ func CreateGateway(ctx context.Context, g Gateway, port uint16, http1HostName st
|
||||
}
|
||||
|
||||
func addInterceptors(handler http.Handler, http1HostName string) http.Handler {
|
||||
handler = http_mw.CallDurationHandler(handler)
|
||||
handler = http1Host(handler, http1HostName)
|
||||
handler = http_mw.CORSInterceptor(handler)
|
||||
handler = http_mw.DefaultTelemetryHandler(handler)
|
||||
|
16
internal/api/grpc/server/middleware/call_interceptor.go
Normal file
16
internal/api/grpc/server/middleware/call_interceptor.go
Normal file
@ -0,0 +1,16 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
)
|
||||
|
||||
func CallDurationHandler() grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
ctx = call.WithTimestamp(ctx)
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ func CreateServer(
|
||||
serverOptions := []grpc.ServerOption{
|
||||
grpc.UnaryInterceptor(
|
||||
grpc_middleware.ChainUnaryServer(
|
||||
middleware.CallDurationHandler(),
|
||||
middleware.DefaultTracingServer(),
|
||||
middleware.MetricsHandler(metricTypes, grpc_api.Probes...),
|
||||
middleware.NoCacheInterceptor(),
|
||||
|
13
internal/api/http/middleware/call_interceptor.go
Normal file
13
internal/api/http/middleware/call_interceptor.go
Normal file
@ -0,0 +1,13 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
)
|
||||
|
||||
func CallDurationHandler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
next.ServeHTTP(w, r.WithContext(call.WithTimestamp(r.Context())))
|
||||
})
|
||||
}
|
@ -187,6 +187,7 @@ func (o *OPStorage) getMaxKeySequence(ctx context.Context) (uint64, error) {
|
||||
return o.eventstore.LatestSequence(ctx,
|
||||
eventstore.NewSearchQueryBuilder(eventstore.ColumnsMaxSequence).
|
||||
ResourceOwner(authz.GetInstance(ctx).InstanceID()).
|
||||
AllowTimeTravel().
|
||||
AddQuery().
|
||||
AggregateTypes(keypair.AggregateType, instance.AggregateType).
|
||||
Builder(),
|
||||
|
@ -2,7 +2,6 @@ package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
@ -18,6 +17,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/auth/repository"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/crdb"
|
||||
@ -73,7 +73,7 @@ type OPStorage struct {
|
||||
assetAPIPrefix func(ctx context.Context) string
|
||||
}
|
||||
|
||||
func NewProvider(ctx context.Context, config Config, defaultLogoutRedirectURI string, externalSecure bool, command *command.Commands, query *query.Queries, repo repository.Repository, encryptionAlg crypto.EncryptionAlgorithm, cryptoKey []byte, es *eventstore.Eventstore, projections *sql.DB, userAgentCookie, instanceHandler, accessHandler func(http.Handler) http.Handler) (op.OpenIDProvider, error) {
|
||||
func NewProvider(ctx context.Context, config Config, defaultLogoutRedirectURI string, externalSecure bool, command *command.Commands, query *query.Queries, repo repository.Repository, encryptionAlg crypto.EncryptionAlgorithm, cryptoKey []byte, es *eventstore.Eventstore, projections *database.DB, userAgentCookie, instanceHandler, accessHandler func(http.Handler) http.Handler) (op.OpenIDProvider, error) {
|
||||
opConfig, err := createOPConfig(config, defaultLogoutRedirectURI, cryptoKey)
|
||||
if err != nil {
|
||||
return nil, caos_errs.ThrowInternal(err, "OIDC-EGrqd", "cannot create op config: %w")
|
||||
@ -169,7 +169,7 @@ func customEndpoints(endpointConfig *EndpointConfig) []op.Option {
|
||||
return options
|
||||
}
|
||||
|
||||
func newStorage(config Config, command *command.Commands, query *query.Queries, repo repository.Repository, encAlg crypto.EncryptionAlgorithm, es *eventstore.Eventstore, projections *sql.DB, externalSecure bool) *OPStorage {
|
||||
func newStorage(config Config, command *command.Commands, query *query.Queries, repo repository.Repository, encAlg crypto.EncryptionAlgorithm, es *eventstore.Eventstore, db *database.DB, externalSecure bool) *OPStorage {
|
||||
return &OPStorage{
|
||||
repo: repo,
|
||||
command: command,
|
||||
@ -182,7 +182,7 @@ func newStorage(config Config, command *command.Commands, query *query.Queries,
|
||||
defaultRefreshTokenIdleExpiration: config.DefaultRefreshTokenIdleExpiration,
|
||||
defaultRefreshTokenExpiration: config.DefaultRefreshTokenExpiration,
|
||||
encAlg: encAlg,
|
||||
locker: crdb.NewLocker(projections, locksTable, signingKey),
|
||||
locker: crdb.NewLocker(db.DB, locksTable, signingKey),
|
||||
assetAPIPrefix: assets.AssetAPI(externalSecure),
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package saml
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
@ -14,6 +13,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/auth/repository"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/crdb"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -38,7 +38,7 @@ func NewProvider(
|
||||
encAlg crypto.EncryptionAlgorithm,
|
||||
certEncAlg crypto.EncryptionAlgorithm,
|
||||
es *eventstore.Eventstore,
|
||||
projections *sql.DB,
|
||||
projections *database.DB,
|
||||
instanceHandler,
|
||||
userAgentCookie,
|
||||
accessHandler func(http.Handler) http.Handler,
|
||||
@ -89,12 +89,12 @@ func newStorage(
|
||||
encAlg crypto.EncryptionAlgorithm,
|
||||
certEncAlg crypto.EncryptionAlgorithm,
|
||||
es *eventstore.Eventstore,
|
||||
projections *sql.DB,
|
||||
db *database.DB,
|
||||
) (*Storage, error) {
|
||||
return &Storage{
|
||||
encAlg: encAlg,
|
||||
certEncAlg: certEncAlg,
|
||||
locker: crdb.NewLocker(projections, locksTable, signingKey),
|
||||
locker: crdb.NewLocker(db.DB, locksTable, signingKey),
|
||||
eventstore: es,
|
||||
repo: repo,
|
||||
command: command,
|
||||
|
@ -88,7 +88,7 @@ func (f *file) Stat() (_ fs.FileInfo, err error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, instanceHandler, accessInterceptor func(http.Handler) http.Handler, customerPortal string) (http.Handler, error) {
|
||||
func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, callDurationInterceptor, instanceHandler, accessInterceptor func(http.Handler) http.Handler, customerPortal string) (http.Handler, error) {
|
||||
fSys, err := fs.Sub(static, "static")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -103,7 +103,7 @@ func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, inst
|
||||
|
||||
handler := mux.NewRouter()
|
||||
|
||||
handler.Use(instanceHandler, security, accessInterceptor)
|
||||
handler.Use(callDurationInterceptor, instanceHandler, security, accessInterceptor)
|
||||
handler.Handle(envRequestPath, middleware.TelemetryHandler()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
url := http_util.BuildOrigin(r.Host, externalSecure)
|
||||
environmentJSON, err := createEnvironmentJSON(url, issuer(r), authz.GetInstance(r.Context()).ConsoleClientID(), customerPortal)
|
||||
|
@ -67,8 +67,8 @@ func CreateLogin(config Config,
|
||||
userAgentCookie,
|
||||
issuerInterceptor,
|
||||
oidcInstanceHandler,
|
||||
samlInstanceHandler mux.MiddlewareFunc,
|
||||
assetCache mux.MiddlewareFunc,
|
||||
samlInstanceHandler,
|
||||
assetCache,
|
||||
accessHandler mux.MiddlewareFunc,
|
||||
userCodeAlg crypto.EncryptionAlgorithm,
|
||||
idpConfigAlg crypto.EncryptionAlgorithm,
|
||||
|
@ -2,7 +2,6 @@ package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/spooler"
|
||||
@ -11,6 +10,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
eventstore2 "github.com/zitadel/zitadel/internal/eventstore"
|
||||
v1 "github.com/zitadel/zitadel/internal/eventstore/v1"
|
||||
es_spol "github.com/zitadel/zitadel/internal/eventstore/v1/spooler"
|
||||
@ -34,7 +34,7 @@ type EsRepository struct {
|
||||
eventstore.OrgRepository
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *sql.DB, esV2 *eventstore2.Eventstore, oidcEncryption crypto.EncryptionAlgorithm, userEncryption crypto.EncryptionAlgorithm) (*EsRepository, error) {
|
||||
func Start(ctx context.Context, conf Config, systemDefaults sd.SystemDefaults, command *command.Commands, queries *query.Queries, dbClient *database.DB, esV2 *eventstore2.Eventstore, oidcEncryption crypto.EncryptionAlgorithm, userEncryption crypto.EncryptionAlgorithm) (*EsRepository, error) {
|
||||
es, err := v1.Start(dbClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -2,11 +2,11 @@ package spooler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/handler"
|
||||
"github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
v1 "github.com/zitadel/zitadel/internal/eventstore/v1"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/spooler"
|
||||
@ -21,11 +21,11 @@ type SpoolerConfig struct {
|
||||
Handlers handler.Configs
|
||||
}
|
||||
|
||||
func StartSpooler(ctx context.Context, c SpoolerConfig, es v1.Eventstore, esV2 *eventstore.Eventstore, view *view.View, client *sql.DB, systemDefaults sd.SystemDefaults, queries *query.Queries) *spooler.Spooler {
|
||||
func StartSpooler(ctx context.Context, c SpoolerConfig, es v1.Eventstore, esV2 *eventstore.Eventstore, view *view.View, client *database.DB, systemDefaults sd.SystemDefaults, queries *query.Queries) *spooler.Spooler {
|
||||
spoolerConfig := spooler.Config{
|
||||
Eventstore: es,
|
||||
EventstoreV2: esV2,
|
||||
Locker: &locker{dbClient: client},
|
||||
Locker: &locker{dbClient: client.DB},
|
||||
ConcurrentWorkers: c.ConcurrentWorkers,
|
||||
ConcurrentInstances: c.ConcurrentInstances,
|
||||
ViewHandlers: handler.Register(ctx, c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, systemDefaults, queries),
|
||||
|
@ -21,15 +21,6 @@ func (v *View) UserByID(userID, instanceID string) (*model.UserView, error) {
|
||||
return view.UserByID(v.Db, userTable, userID, instanceID)
|
||||
}
|
||||
|
||||
func (v *View) UserByUsername(userName, instanceID string) (*model.UserView, error) {
|
||||
query, err := query.NewUserUsernameSearchQuery(userName, query.TextEquals)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return v.userByID(instanceID, query)
|
||||
}
|
||||
|
||||
func (v *View) UserByLoginName(loginName, instanceID string) (*model.UserView, error) {
|
||||
loginNameQuery, err := query.NewUserLoginNamesSearchQuery(loginName)
|
||||
if err != nil {
|
||||
|
@ -1,11 +1,10 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
eventstore "github.com/zitadel/zitadel/internal/eventstore/v1"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -19,7 +18,7 @@ type View struct {
|
||||
es eventstore.Eventstore
|
||||
}
|
||||
|
||||
func StartView(sqlClient *sql.DB, keyAlgorithm crypto.EncryptionAlgorithm, queries *query.Queries, idGenerator id.Generator, es eventstore.Eventstore) (*View, error) {
|
||||
func StartView(sqlClient *database.DB, keyAlgorithm crypto.EncryptionAlgorithm, queries *query.Queries, idGenerator id.Generator, es eventstore.Eventstore) (*View, error) {
|
||||
gorm, err := gorm.Open("postgres", sqlClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -9,15 +9,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
type AuthRequestCache struct {
|
||||
client *sql.DB
|
||||
client *database.DB
|
||||
}
|
||||
|
||||
func Start(dbClient *sql.DB) *AuthRequestCache {
|
||||
func Start(dbClient *database.DB) *AuthRequestCache {
|
||||
return &AuthRequestCache{
|
||||
client: dbClient,
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
package authz
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/authz/repository"
|
||||
"github.com/zitadel/zitadel/internal/authz/repository/eventsourcing"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
)
|
||||
|
||||
func Start(queries *query.Queries, dbClient *sql.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure bool) (repository.Repository, error) {
|
||||
func Start(queries *query.Queries, dbClient *database.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure bool) (repository.Repository, error) {
|
||||
return eventsourcing.Start(queries, dbClient, keyEncryptionAlgorithm, externalSecure)
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/authz/repository"
|
||||
"github.com/zitadel/zitadel/internal/authz/repository/eventsourcing/eventstore"
|
||||
authz_view "github.com/zitadel/zitadel/internal/authz/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
v1 "github.com/zitadel/zitadel/internal/eventstore/v1"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -18,7 +18,7 @@ type EsRepository struct {
|
||||
eventstore.TokenVerifierRepo
|
||||
}
|
||||
|
||||
func Start(queries *query.Queries, dbClient *sql.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure bool) (repository.Repository, error) {
|
||||
func Start(queries *query.Queries, dbClient *database.DB, keyEncryptionAlgorithm crypto.EncryptionAlgorithm, externalSecure bool) (repository.Repository, error) {
|
||||
es, err := v1.Start(dbClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1,8 +1,7 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
|
||||
@ -15,7 +14,7 @@ type View struct {
|
||||
idGenerator id.Generator
|
||||
}
|
||||
|
||||
func StartView(sqlClient *sql.DB, idGenerator id.Generator, queries *query.Queries) (*View, error) {
|
||||
func StartView(sqlClient *database.DB, idGenerator id.Generator, queries *query.Queries) (*View, error) {
|
||||
gorm, err := gorm.Open("postgres", sqlClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -9,7 +9,6 @@ type quotaWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
unit quota.Unit
|
||||
active bool
|
||||
config *quota.AddedEvent
|
||||
}
|
||||
|
||||
// newQuotaWriteModel aggregateId is filled by reducing unit matching events
|
||||
@ -43,11 +42,9 @@ func (wm *quotaWriteModel) Reduce() error {
|
||||
case *quota.AddedEvent:
|
||||
wm.AggregateID = e.Aggregate().ID
|
||||
wm.active = true
|
||||
wm.config = e
|
||||
case *quota.RemovedEvent:
|
||||
wm.AggregateID = e.Aggregate().ID
|
||||
wm.active = false
|
||||
wm.config = nil
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
|
@ -1,45 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/quota"
|
||||
)
|
||||
|
||||
type quotaNotificationsWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
periodStart time.Time
|
||||
latestNotifiedThresholds map[string]uint16
|
||||
}
|
||||
|
||||
func newQuotaNotificationsWriteModel(aggregateId, instanceId, resourceOwner string, periodStart time.Time) *quotaNotificationsWriteModel {
|
||||
return "aNotificationsWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: aggregateId,
|
||||
InstanceID: instanceId,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
periodStart: periodStart,
|
||||
latestNotifiedThresholds: make(map[string]uint16),
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *quotaNotificationsWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
InstanceID(wm.InstanceID).
|
||||
AggregateTypes(quota.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
CreationDateAfter(wm.periodStart).
|
||||
EventTypes(quota.NotifiedEventType).Builder()
|
||||
}
|
||||
|
||||
func (wm *quotaNotificationsWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
e := event.(*quota.NotifiedEvent)
|
||||
wm.latestNotifiedThresholds[e.ID] = e.Threshold
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/repository/quota"
|
||||
)
|
||||
|
||||
func (c *Commands) GetCurrentQuotaPeriod(ctx context.Context, instanceID string, unit quota.Unit) (*quota.AddedEvent, time.Time, error) {
|
||||
wm, err := c.getQuotaWriteModel(ctx, instanceID, instanceID, unit)
|
||||
if err != nil || !wm.active {
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
|
||||
return wm.config, pushPeriodStart(wm.config.From, wm.config.ResetInterval, time.Now()), nil
|
||||
}
|
||||
|
||||
func pushPeriodStart(from time.Time, interval time.Duration, now time.Time) time.Time {
|
||||
next := from.Add(interval)
|
||||
if next.After(now) {
|
||||
return from
|
||||
}
|
||||
return pushPeriodStart(next, interval, now)
|
||||
}
|
@ -2,6 +2,7 @@ package cockroach
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -89,6 +90,15 @@ func (c *Config) Type() string {
|
||||
return "cockroach"
|
||||
}
|
||||
|
||||
func (c *Config) Timetravel(d time.Duration) string {
|
||||
// verify that it is at least 1 micro second
|
||||
if d < time.Microsecond {
|
||||
d = time.Microsecond
|
||||
}
|
||||
|
||||
return fmt.Sprintf(" AS OF SYSTEM TIME '-%d µs' ", d.Microseconds())
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string
|
||||
Password string
|
||||
|
61
internal/database/cockroach/config_test.go
Normal file
61
internal/database/cockroach/config_test.go
Normal file
@ -0,0 +1,61 @@
|
||||
package cockroach
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestConfig_Timetravel(t *testing.T) {
|
||||
type args struct {
|
||||
d time.Duration
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "no duration",
|
||||
args: args{
|
||||
d: 0,
|
||||
},
|
||||
want: " AS OF SYSTEM TIME '-1 µs' ",
|
||||
},
|
||||
{
|
||||
name: "less than microsecond",
|
||||
args: args{
|
||||
d: 100 * time.Nanosecond,
|
||||
},
|
||||
want: " AS OF SYSTEM TIME '-1 µs' ",
|
||||
},
|
||||
{
|
||||
name: "10 microseconds",
|
||||
args: args{
|
||||
d: 10 * time.Microsecond,
|
||||
},
|
||||
want: " AS OF SYSTEM TIME '-10 µs' ",
|
||||
},
|
||||
{
|
||||
name: "10 milliseconds",
|
||||
args: args{
|
||||
d: 10 * time.Millisecond,
|
||||
},
|
||||
want: " AS OF SYSTEM TIME '-10000 µs' ",
|
||||
},
|
||||
{
|
||||
name: "1 second",
|
||||
args: args{
|
||||
d: 1 * time.Second,
|
||||
},
|
||||
want: " AS OF SYSTEM TIME '-1000000 µs' ",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
c := &Config{}
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := c.Timetravel(tt.args.d); got != tt.want {
|
||||
t.Errorf("Config.Timetravel() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -19,7 +19,12 @@ func (c *Config) SetConnector(connector dialect.Connector) {
|
||||
c.connector = connector
|
||||
}
|
||||
|
||||
func Connect(config Config, useAdmin bool) (*sql.DB, error) {
|
||||
type DB struct {
|
||||
*sql.DB
|
||||
dialect.Database
|
||||
}
|
||||
|
||||
func Connect(config Config, useAdmin bool) (*DB, error) {
|
||||
client, err := config.connector.Connect(useAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -29,7 +34,10 @@ func Connect(config Config, useAdmin bool) (*sql.DB, error) {
|
||||
return nil, errors.ThrowPreconditionFailed(err, "DATAB-0pIWD", "Errors.Database.Connection.Failed")
|
||||
}
|
||||
|
||||
return client, nil
|
||||
return &DB{
|
||||
DB: client,
|
||||
Database: config.connector,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DecodeHook(from, to reflect.Value) (interface{}, error) {
|
||||
@ -61,7 +69,7 @@ func DecodeHook(from, to reflect.Value) (interface{}, error) {
|
||||
return Config{connector: connector}, nil
|
||||
}
|
||||
|
||||
func (c Config) Database() string {
|
||||
func (c Config) DatabaseName() string {
|
||||
return c.connector.DatabaseName()
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package dialect
|
||||
import (
|
||||
"database/sql"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@ -29,10 +30,15 @@ type Matcher interface {
|
||||
|
||||
type Connector interface {
|
||||
Connect(useAdmin bool) (*sql.DB, error)
|
||||
Password() string
|
||||
Database
|
||||
}
|
||||
|
||||
type Database interface {
|
||||
DatabaseName() string
|
||||
Username() string
|
||||
Password() string
|
||||
Type() string
|
||||
Timetravel(time.Duration) string
|
||||
}
|
||||
|
||||
func Register(matcher Matcher, config Connector, isDefault bool) {
|
||||
|
@ -89,6 +89,10 @@ func (c *Config) Type() string {
|
||||
return "postgres"
|
||||
}
|
||||
|
||||
func (c *Config) Timetravel(time.Duration) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string
|
||||
Password string
|
||||
|
@ -1,16 +1,16 @@
|
||||
package eventstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
z_sql "github.com/zitadel/zitadel/internal/eventstore/repository/sql"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
PushTimeout time.Duration
|
||||
Client *sql.DB
|
||||
Client *database.DB
|
||||
|
||||
repo repository.Repository
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||
@ -19,7 +20,7 @@ var (
|
||||
type StatementHandlerConfig struct {
|
||||
handler.ProjectionHandlerConfig
|
||||
|
||||
Client *sql.DB
|
||||
Client *database.DB
|
||||
SequenceTable string
|
||||
LockTable string
|
||||
FailedEventsTable string
|
||||
@ -34,7 +35,7 @@ type StatementHandler struct {
|
||||
*handler.ProjectionHandler
|
||||
Locker
|
||||
|
||||
client *sql.DB
|
||||
client *database.DB
|
||||
sequenceTable string
|
||||
currentSequenceStmt string
|
||||
updateSequencesBaseStmt string
|
||||
@ -74,7 +75,7 @@ func NewStatementHandler(
|
||||
aggregates: aggregateTypes,
|
||||
reduces: reduces,
|
||||
bulkLimit: config.BulkLimit,
|
||||
Locker: NewLocker(config.Client, config.LockTable, config.ProjectionName),
|
||||
Locker: NewLocker(config.Client.DB, config.LockTable, config.ProjectionName),
|
||||
initCheck: config.InitCheck,
|
||||
initialized: make(chan bool),
|
||||
}
|
||||
@ -96,7 +97,7 @@ func (h *StatementHandler) SearchQuery(ctx context.Context, instanceIDs []string
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
queryBuilder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).Limit(h.bulkLimit)
|
||||
queryBuilder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).Limit(h.bulkLimit).AllowTimeTravel()
|
||||
|
||||
for _, aggregateType := range h.aggregates {
|
||||
for _, instanceID := range instanceIDs {
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
@ -114,6 +115,7 @@ func TestProjectionHandler_SearchQuery(t *testing.T) {
|
||||
},
|
||||
SearchQueryBuilder: eventstore.
|
||||
NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
AllowTimeTravel().
|
||||
AddQuery().
|
||||
AggregateTypes("testAgg").
|
||||
SequenceGreater(5).
|
||||
@ -143,6 +145,7 @@ func TestProjectionHandler_SearchQuery(t *testing.T) {
|
||||
},
|
||||
SearchQueryBuilder: eventstore.
|
||||
NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
AllowTimeTravel().
|
||||
AddQuery().
|
||||
AggregateTypes("testAgg").
|
||||
SequenceGreater(5).
|
||||
@ -171,7 +174,9 @@ func TestProjectionHandler_SearchQuery(t *testing.T) {
|
||||
},
|
||||
SequenceTable: tt.fields.sequenceTable,
|
||||
BulkLimit: tt.fields.bulkLimit,
|
||||
Client: client,
|
||||
Client: &database.DB{
|
||||
DB: client,
|
||||
},
|
||||
})
|
||||
|
||||
h.aggregates = tt.fields.aggregates
|
||||
@ -549,7 +554,9 @@ func TestStatementHandler_Update(t *testing.T) {
|
||||
sequenceTable: "my_sequences",
|
||||
currentSequenceStmt: fmt.Sprintf(currentSequenceStmtFormat, "my_sequences"),
|
||||
updateSequencesBaseStmt: fmt.Sprintf(updateCurrentSequencesStmtFormat, "my_sequences"),
|
||||
client: client,
|
||||
client: &database.DB{
|
||||
DB: client,
|
||||
},
|
||||
}
|
||||
|
||||
h.aggregates = tt.fields.aggregates
|
||||
@ -1121,7 +1128,9 @@ func TestStatementHandler_executeStmts(t *testing.T) {
|
||||
ProjectionName: tt.fields.projectionName,
|
||||
RequeueEvery: 0,
|
||||
},
|
||||
Client: client,
|
||||
Client: &database.DB{
|
||||
DB: client,
|
||||
},
|
||||
FailedEventsTable: tt.fields.failedEventsTable,
|
||||
MaxFailureCount: tt.fields.maxFailureCount,
|
||||
},
|
||||
|
@ -194,7 +194,7 @@ func (h *ProjectionHandler) schedule(ctx context.Context) {
|
||||
var succeededOnce bool
|
||||
var err error
|
||||
// get every instance id except empty (system)
|
||||
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsInstanceIDs).AddQuery().ExcludedInstanceID("")
|
||||
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsInstanceIDs).AllowTimeTravel().AddQuery().ExcludedInstanceID("")
|
||||
for range h.triggerProjection.C {
|
||||
if !succeededOnce {
|
||||
// (re)check if it has succeeded in the meantime
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cockroachdb/cockroach-go/v2/testserver"
|
||||
"github.com/zitadel/logging"
|
||||
@ -14,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
testCRDBClient *sql.DB
|
||||
testCRDBClient *database.DB
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@ -23,7 +24,11 @@ func TestMain(m *testing.M) {
|
||||
logging.WithFields("error", err).Fatal("unable to start db")
|
||||
}
|
||||
|
||||
testCRDBClient, err = sql.Open("postgres", ts.PGURL().String())
|
||||
testCRDBClient = &database.DB{
|
||||
Database: new(testDB),
|
||||
}
|
||||
|
||||
testCRDBClient.DB, err = sql.Open("postgres", ts.PGURL().String())
|
||||
if err != nil {
|
||||
logging.WithFields("error", err).Fatal("unable to connect to db")
|
||||
}
|
||||
@ -39,7 +44,7 @@ func TestMain(m *testing.M) {
|
||||
ts.Stop()
|
||||
}()
|
||||
|
||||
if err = initDB(testCRDBClient); err != nil {
|
||||
if err = initDB(testCRDBClient.DB); err != nil {
|
||||
logging.WithFields("error", err).Fatal("migrations failed")
|
||||
}
|
||||
|
||||
@ -57,10 +62,20 @@ func initDB(db *sql.DB) error {
|
||||
})
|
||||
err := initialise.Init(db,
|
||||
initialise.VerifyUser(config.Username(), ""),
|
||||
initialise.VerifyDatabase(config.Database()),
|
||||
initialise.VerifyGrant(config.Database(), config.Username()))
|
||||
initialise.VerifyDatabase(config.DatabaseName()),
|
||||
initialise.VerifyGrant(config.DatabaseName(), config.Username()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return initialise.VerifyZitadel(db, *config)
|
||||
}
|
||||
|
||||
type testDB struct{}
|
||||
|
||||
func (_ *testDB) Timetravel(time.Duration) string { return " AS OF SYSTEM TIME '-1 ms' " }
|
||||
|
||||
func (*testDB) DatabaseName() string { return "db" }
|
||||
|
||||
func (*testDB) Username() string { return "user" }
|
||||
|
||||
func (*testDB) Type() string { return "type" }
|
||||
|
@ -2,7 +2,7 @@ package eventstore
|
||||
|
||||
import "time"
|
||||
|
||||
//ReadModel is the minimum representation of a read model.
|
||||
// ReadModel is the minimum representation of a read model.
|
||||
// It implements a basic reducer
|
||||
// it might be saved in a database or in memory
|
||||
type ReadModel struct {
|
||||
@ -15,14 +15,13 @@ type ReadModel struct {
|
||||
InstanceID string `json:"-"`
|
||||
}
|
||||
|
||||
//AppendEvents adds all the events to the read model.
|
||||
// AppendEvents adds all the events to the read model.
|
||||
// The function doesn't compute the new state of the read model
|
||||
func (rm *ReadModel) AppendEvents(events ...Event) *ReadModel {
|
||||
func (rm *ReadModel) AppendEvents(events ...Event) {
|
||||
rm.Events = append(rm.Events, events...)
|
||||
return rm
|
||||
}
|
||||
|
||||
//Reduce is the basic implementation of reducer
|
||||
// Reduce is the basic implementation of reducer
|
||||
// If this function is extended the extending function should be the last step
|
||||
func (rm *ReadModel) Reduce() error {
|
||||
if len(rm.Events) == 0 {
|
||||
|
@ -8,11 +8,12 @@ import (
|
||||
|
||||
// SearchQuery defines the which and how data are queried
|
||||
type SearchQuery struct {
|
||||
Columns Columns
|
||||
Limit uint64
|
||||
Desc bool
|
||||
Filters [][]*Filter
|
||||
Tx *sql.Tx
|
||||
Columns Columns
|
||||
Limit uint64
|
||||
Desc bool
|
||||
Filters [][]*Filter
|
||||
Tx *sql.Tx
|
||||
AllowTimeTravel bool
|
||||
}
|
||||
|
||||
// Columns defines which fields of the event are needed for the query
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/lib/pq"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
@ -97,19 +98,19 @@ const (
|
||||
)
|
||||
|
||||
type CRDB struct {
|
||||
client *sql.DB
|
||||
*database.DB
|
||||
}
|
||||
|
||||
func NewCRDB(client *sql.DB) *CRDB {
|
||||
func NewCRDB(client *database.DB) *CRDB {
|
||||
return &CRDB{client}
|
||||
}
|
||||
|
||||
func (db *CRDB) Health(ctx context.Context) error { return db.client.Ping() }
|
||||
func (db *CRDB) Health(ctx context.Context) error { return db.Ping() }
|
||||
|
||||
// Push adds all events to the eventstreams of the aggregates.
|
||||
// This call is transaction save. The transaction will be rolled back if one event fails
|
||||
func (db *CRDB) Push(ctx context.Context, events []*repository.Event, uniqueConstraints ...*repository.UniqueConstraint) error {
|
||||
err := crdb.ExecuteTx(ctx, db.client, nil, func(tx *sql.Tx) error {
|
||||
err := crdb.ExecuteTx(ctx, db.DB.DB, nil, func(tx *sql.Tx) error {
|
||||
|
||||
var (
|
||||
previousAggregateSequence Sequence
|
||||
@ -159,7 +160,7 @@ func (db *CRDB) Push(ctx context.Context, events []*repository.Event, uniqueCons
|
||||
var instanceRegexp = regexp.MustCompile(`eventstore\.i_[0-9a-zA-Z]{1,}_seq`)
|
||||
|
||||
func (db *CRDB) CreateInstance(ctx context.Context, instanceID string) error {
|
||||
row := db.client.QueryRowContext(ctx, "SELECT CONCAT('eventstore.i_', $1::TEXT, '_seq')", instanceID)
|
||||
row := db.QueryRowContext(ctx, "SELECT CONCAT('eventstore.i_', $1::TEXT, '_seq')", instanceID)
|
||||
if row.Err() != nil {
|
||||
return caos_errs.ThrowInvalidArgument(row.Err(), "SQL-7gtFA", "Errors.InvalidArgument")
|
||||
}
|
||||
@ -168,7 +169,7 @@ func (db *CRDB) CreateInstance(ctx context.Context, instanceID string) error {
|
||||
return caos_errs.ThrowInvalidArgument(err, "SQL-7gtFA", "Errors.InvalidArgument")
|
||||
}
|
||||
|
||||
if _, err := db.client.ExecContext(ctx, "CREATE SEQUENCE "+sequenceName); err != nil {
|
||||
if _, err := db.ExecContext(ctx, "CREATE SEQUENCE "+sequenceName); err != nil {
|
||||
return caos_errs.ThrowInternal(err, "SQL-7gtFA", "Errors.Internal")
|
||||
}
|
||||
|
||||
@ -249,7 +250,7 @@ func (db *CRDB) InstanceIDs(ctx context.Context, searchQuery *repository.SearchQ
|
||||
}
|
||||
|
||||
func (db *CRDB) db() *sql.DB {
|
||||
return db.client
|
||||
return db.DB.DB
|
||||
}
|
||||
|
||||
func (db *CRDB) orderByEventSequence(desc bool) string {
|
||||
|
@ -437,7 +437,10 @@ func TestCRDB_Push_OneAggregate(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: testCRDBClient,
|
||||
DB: &database.DB{
|
||||
DB: testCRDBClient,
|
||||
Database: new(testDB),
|
||||
},
|
||||
}
|
||||
if tt.args.uniqueDataType != "" && tt.args.uniqueDataField != "" {
|
||||
err := fillUniqueData(tt.args.uniqueDataType, tt.args.uniqueDataField, tt.args.uniqueDataInstanceID)
|
||||
@ -561,7 +564,10 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: testCRDBClient,
|
||||
DB: &database.DB{
|
||||
DB: testCRDBClient,
|
||||
Database: new(testDB),
|
||||
},
|
||||
}
|
||||
if err := db.Push(context.Background(), tt.args.events); (err != nil) != tt.res.wantErr {
|
||||
t.Errorf("CRDB.Push() error = %v, wantErr %v", err, tt.res.wantErr)
|
||||
@ -638,7 +644,7 @@ func TestCRDB_CreateInstance(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: testCRDBClient,
|
||||
DB: &database.DB{DB: testCRDBClient},
|
||||
}
|
||||
|
||||
if err := db.CreateInstance(context.Background(), tt.args.instanceID); (err != nil) != tt.res.wantErr {
|
||||
@ -776,7 +782,10 @@ func TestCRDB_Push_Parallel(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: testCRDBClient,
|
||||
DB: &database.DB{
|
||||
DB: testCRDBClient,
|
||||
Database: new(testDB),
|
||||
},
|
||||
}
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
@ -897,7 +906,10 @@ func TestCRDB_Filter(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: testCRDBClient,
|
||||
DB: &database.DB{
|
||||
DB: testCRDBClient,
|
||||
Database: new(testDB),
|
||||
},
|
||||
}
|
||||
|
||||
// setup initial data for query
|
||||
@ -987,7 +999,10 @@ func TestCRDB_LatestSequence(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: testCRDBClient,
|
||||
DB: &database.DB{
|
||||
DB: testCRDBClient,
|
||||
Database: new(testDB),
|
||||
},
|
||||
}
|
||||
|
||||
// setup initial data for query
|
||||
@ -1131,7 +1146,10 @@ func TestCRDB_Push_ResourceOwner(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: testCRDBClient,
|
||||
DB: &database.DB{
|
||||
DB: testCRDBClient,
|
||||
Database: new(testDB),
|
||||
},
|
||||
}
|
||||
if err := db.Push(context.Background(), tt.args.events); err != nil {
|
||||
t.Errorf("CRDB.Push() error = %v", err)
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cockroachdb/cockroach-go/v2/testserver"
|
||||
"github.com/zitadel/logging"
|
||||
@ -53,8 +54,8 @@ func initDB(db *sql.DB) error {
|
||||
|
||||
err := initialise.Init(db,
|
||||
initialise.VerifyUser(config.Username(), ""),
|
||||
initialise.VerifyDatabase(config.Database()),
|
||||
initialise.VerifyGrant(config.Database(), config.Username()))
|
||||
initialise.VerifyDatabase(config.DatabaseName()),
|
||||
initialise.VerifyGrant(config.DatabaseName(), config.Username()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -66,3 +67,13 @@ func fillUniqueData(unique_type, field, instanceID string) error {
|
||||
_, err := testCRDBClient.Exec("INSERT INTO eventstore.unique_constraints (unique_type, unique_field, instance_id) VALUES ($1, $2, $3)", unique_type, field, instanceID)
|
||||
return err
|
||||
}
|
||||
|
||||
type testDB struct{}
|
||||
|
||||
func (_ *testDB) Timetravel(time.Duration) string { return " AS OF SYSTEM TIME '-1 ms' " }
|
||||
|
||||
func (*testDB) DatabaseName() string { return "db" }
|
||||
|
||||
func (*testDB) Username() string { return "user" }
|
||||
|
||||
func (*testDB) Type() string { return "type" }
|
||||
|
@ -10,6 +10,8 @@ import (
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/database/dialect"
|
||||
z_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
@ -24,6 +26,7 @@ type querier interface {
|
||||
instanceIDsQuery() string
|
||||
db() *sql.DB
|
||||
orderByEventSequence(desc bool) string
|
||||
dialect.Database
|
||||
}
|
||||
|
||||
type scan func(dest ...interface{}) error
|
||||
@ -34,6 +37,11 @@ func query(ctx context.Context, criteria querier, searchQuery *repository.Search
|
||||
if where == "" || query == "" {
|
||||
return z_errors.ThrowInvalidArgument(nil, "SQL-rWeBw", "invalid query factory")
|
||||
}
|
||||
if searchQuery.Tx == nil {
|
||||
if travel := prepareTimeTravel(ctx, criteria, searchQuery.AllowTimeTravel); travel != "" {
|
||||
query += travel
|
||||
}
|
||||
}
|
||||
query += where
|
||||
|
||||
if searchQuery.Columns == repository.ColumnsEvent {
|
||||
@ -85,6 +93,14 @@ func prepareColumns(criteria querier, columns repository.Columns) (string, func(
|
||||
}
|
||||
}
|
||||
|
||||
func prepareTimeTravel(ctx context.Context, criteria querier, allow bool) string {
|
||||
if !allow {
|
||||
return ""
|
||||
}
|
||||
took := call.Took(ctx)
|
||||
return criteria.Timetravel(took)
|
||||
}
|
||||
|
||||
func maxSequenceScanner(row scan, dest interface{}) (err error) {
|
||||
sequence, ok := dest.(*Sequence)
|
||||
if !ok {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
@ -537,7 +538,10 @@ func Test_query_events_with_crdb(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db := &CRDB{
|
||||
client: tt.fields.client,
|
||||
DB: &database.DB{
|
||||
DB: tt.fields.client,
|
||||
Database: new(testDB),
|
||||
},
|
||||
}
|
||||
|
||||
// setup initial data for query
|
||||
@ -657,6 +661,36 @@ func Test_query_events_mocked(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with limit and order by desc as of system time",
|
||||
args: args{
|
||||
dest: &[]*repository.Event{},
|
||||
query: &repository.SearchQuery{
|
||||
Columns: repository.ColumnsEvent,
|
||||
Desc: true,
|
||||
Limit: 5,
|
||||
AllowTimeTravel: true,
|
||||
Filters: [][]*repository.Filter{
|
||||
{
|
||||
{
|
||||
Field: repository.FieldAggregateType,
|
||||
Value: repository.AggregateType("user"),
|
||||
Operation: repository.OperationEquals,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fields: fields{
|
||||
mock: newMockClient(t).expectQuery(t,
|
||||
`SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, previous_aggregate_type_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events AS OF SYSTEM TIME '-1 ms' WHERE \( aggregate_type = \$1 \) ORDER BY event_sequence DESC LIMIT \$2`,
|
||||
[]driver.Value{repository.AggregateType("user"), uint64(5)},
|
||||
),
|
||||
},
|
||||
res: res{
|
||||
wantErr: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "error sql conn closed",
|
||||
args: args{
|
||||
@ -786,9 +820,11 @@ func Test_query_events_mocked(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
crdb := &CRDB{}
|
||||
crdb := &CRDB{DB: &database.DB{
|
||||
Database: new(testDB),
|
||||
}}
|
||||
if tt.fields.mock != nil {
|
||||
crdb.client = tt.fields.mock.client
|
||||
crdb.DB.DB = tt.fields.mock.client
|
||||
}
|
||||
|
||||
err := query(context.Background(), crdb, tt.args.query, tt.args.dest)
|
||||
|
@ -12,14 +12,15 @@ import (
|
||||
// SearchQueryBuilder represents the builder for your filter
|
||||
// if invalid data are set the filter will fail
|
||||
type SearchQueryBuilder struct {
|
||||
columns repository.Columns
|
||||
limit uint64
|
||||
desc bool
|
||||
resourceOwner string
|
||||
instanceID string
|
||||
editorUser string
|
||||
queries []*SearchQuery
|
||||
tx *sql.Tx
|
||||
columns repository.Columns
|
||||
limit uint64
|
||||
desc bool
|
||||
resourceOwner string
|
||||
instanceID string
|
||||
editorUser string
|
||||
queries []*SearchQuery
|
||||
tx *sql.Tx
|
||||
allowTimeTravel bool
|
||||
}
|
||||
|
||||
type SearchQuery struct {
|
||||
@ -130,6 +131,13 @@ func (builder *SearchQueryBuilder) EditorUser(id string) *SearchQueryBuilder {
|
||||
return builder
|
||||
}
|
||||
|
||||
// AllowTimeTravel activates the time travel feature of the database if supported
|
||||
// The queries will be made based on the call time
|
||||
func (builder *SearchQueryBuilder) AllowTimeTravel() *SearchQueryBuilder {
|
||||
builder.allowTimeTravel = true
|
||||
return builder
|
||||
}
|
||||
|
||||
// AddQuery creates a new sub query.
|
||||
// All fields in the sub query are AND-connected in the storage request.
|
||||
// Multiple sub queries are OR-connected in the storage request.
|
||||
@ -264,11 +272,12 @@ func (builder *SearchQueryBuilder) build(instanceID string) (*repository.SearchQ
|
||||
}
|
||||
|
||||
return &repository.SearchQuery{
|
||||
Columns: builder.columns,
|
||||
Limit: builder.limit,
|
||||
Desc: builder.desc,
|
||||
Filters: filters,
|
||||
Tx: builder.tx,
|
||||
Columns: builder.columns,
|
||||
Limit: builder.limit,
|
||||
Desc: builder.desc,
|
||||
Filters: filters,
|
||||
Tx: builder.tx,
|
||||
AllowTimeTravel: builder.allowTimeTravel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@ package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/internal/repository"
|
||||
z_sql "github.com/zitadel/zitadel/internal/eventstore/v1/internal/repository/sql"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
@ -22,7 +22,7 @@ type eventstore struct {
|
||||
repo repository.Repository
|
||||
}
|
||||
|
||||
func Start(db *sql.DB) (Eventstore, error) {
|
||||
func Start(db *database.DB) (Eventstore, error) {
|
||||
return &eventstore{
|
||||
repo: z_sql.Start(db),
|
||||
}, nil
|
||||
|
@ -1,10 +1,10 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
)
|
||||
|
||||
func Start(client *sql.DB) *SQL {
|
||||
func Start(client *database.DB) *SQL {
|
||||
return &SQL{
|
||||
client: client,
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
selectEscaped = `SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore\.events WHERE \( aggregate_type = \$1`
|
||||
selectEscaped = `SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore\.events AS OF SYSTEM TIME '-1 ms' WHERE \( aggregate_type = \$1`
|
||||
)
|
||||
|
||||
var (
|
||||
@ -172,14 +172,14 @@ func (db *dbMock) expectFilterEventsError(returnedErr error) *dbMock {
|
||||
}
|
||||
|
||||
func (db *dbMock) expectLatestSequenceFilter(aggregateType string, sequence Sequence) *dbMock {
|
||||
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events WHERE \( aggregate_type = \$1 \)`).
|
||||
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events AS OF SYSTEM TIME '-1 ms' WHERE \( aggregate_type = \$1 \)`).
|
||||
WithArgs(aggregateType).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"max_sequence"}).AddRow(sequence))
|
||||
return db
|
||||
}
|
||||
|
||||
func (db *dbMock) expectLatestSequenceFilterError(aggregateType string, err error) *dbMock {
|
||||
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events WHERE \( aggregate_type = \$1 \)`).
|
||||
db.mock.ExpectQuery(`SELECT MAX\(event_sequence\) FROM eventstore\.events AS OF SYSTEM TIME '-1 ms' WHERE \( aggregate_type = \$1 \)`).
|
||||
WithArgs(aggregateType).WillReturnError(err)
|
||||
return db
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
@ -16,16 +17,16 @@ type Querier interface {
|
||||
}
|
||||
|
||||
func (db *SQL) Filter(ctx context.Context, searchQuery *es_models.SearchQueryFactory) (events []*es_models.Event, err error) {
|
||||
return filter(db.client, searchQuery)
|
||||
return filter(ctx, db.client, searchQuery)
|
||||
}
|
||||
|
||||
func filter(querier Querier, searchQuery *es_models.SearchQueryFactory) (events []*es_models.Event, err error) {
|
||||
query, limit, values, rowScanner := buildQuery(searchQuery)
|
||||
func filter(ctx context.Context, db *database.DB, searchQuery *es_models.SearchQueryFactory) (events []*es_models.Event, err error) {
|
||||
query, limit, values, rowScanner := buildQuery(ctx, db, searchQuery)
|
||||
if query == "" {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "SQL-rWeBw", "invalid query factory")
|
||||
}
|
||||
|
||||
rows, err := querier.Query(query, values...)
|
||||
rows, err := db.Query(query, values...)
|
||||
if err != nil {
|
||||
logging.New().WithError(err).Info("query failed")
|
||||
return nil, errors.ThrowInternal(err, "SQL-IJuyR", "unable to filter events")
|
||||
@ -48,7 +49,7 @@ func filter(querier Querier, searchQuery *es_models.SearchQueryFactory) (events
|
||||
}
|
||||
|
||||
func (db *SQL) LatestSequence(ctx context.Context, queryFactory *es_models.SearchQueryFactory) (uint64, error) {
|
||||
query, _, values, rowScanner := buildQuery(queryFactory)
|
||||
query, _, values, rowScanner := buildQuery(ctx, db.client, queryFactory)
|
||||
if query == "" {
|
||||
return 0, errors.ThrowInvalidArgument(nil, "SQL-rWeBw", "invalid query factory")
|
||||
}
|
||||
@ -63,7 +64,7 @@ func (db *SQL) LatestSequence(ctx context.Context, queryFactory *es_models.Searc
|
||||
}
|
||||
|
||||
func (db *SQL) InstanceIDs(ctx context.Context, queryFactory *es_models.SearchQueryFactory) ([]string, error) {
|
||||
query, _, values, rowScanner := buildQuery(queryFactory)
|
||||
query, _, values, rowScanner := buildQuery(ctx, db.client, queryFactory)
|
||||
if query == "" {
|
||||
return nil, errors.ThrowInvalidArgument(nil, "SQL-Sfwg2", "invalid query factory")
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
@ -122,7 +123,7 @@ func TestSQL_Filter(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sql := &SQL{
|
||||
client: tt.fields.client.sqlClient,
|
||||
client: &database.DB{DB: tt.fields.client.sqlClient, Database: new(testDB)},
|
||||
}
|
||||
events, err := sql.Filter(context.Background(), tt.args.searchQuery)
|
||||
if (err != nil) != tt.res.wantErr {
|
||||
@ -217,7 +218,7 @@ func TestSQL_LatestSequence(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sql := &SQL{
|
||||
client: tt.fields.client.sqlClient,
|
||||
client: &database.DB{DB: tt.fields.client.sqlClient, Database: new(testDB)},
|
||||
}
|
||||
sequence, err := sql.LatestSequence(context.Background(), tt.args.searchQuery)
|
||||
if (err != nil) != tt.res.wantErr {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -9,6 +10,8 @@ import (
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/database/dialect"
|
||||
z_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
@ -30,7 +33,7 @@ const (
|
||||
" FROM eventstore.events"
|
||||
)
|
||||
|
||||
func buildQuery(queryFactory *es_models.SearchQueryFactory) (query string, limit uint64, values []interface{}, rowScanner func(s scan, dest interface{}) error) {
|
||||
func buildQuery(ctx context.Context, db dialect.Database, queryFactory *es_models.SearchQueryFactory) (query string, limit uint64, values []interface{}, rowScanner func(s scan, dest interface{}) error) {
|
||||
searchQuery, err := queryFactory.Build()
|
||||
if err != nil {
|
||||
logging.New().WithError(err).Warn("search query factory invalid")
|
||||
@ -41,6 +44,10 @@ func buildQuery(queryFactory *es_models.SearchQueryFactory) (query string, limit
|
||||
if where == "" || query == "" {
|
||||
return "", 0, nil, nil
|
||||
}
|
||||
|
||||
if travel := db.Timetravel(call.Took(ctx)); travel != "" {
|
||||
query += travel
|
||||
}
|
||||
query += where
|
||||
|
||||
if searchQuery.Columns == es_models.Columns_Event {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"reflect"
|
||||
"testing"
|
||||
@ -435,7 +436,7 @@ func Test_buildQuery(t *testing.T) {
|
||||
queryFactory: es_models.NewSearchQueryFactory().OrderDesc().AddQuery().AggregateTypes("user").Factory(),
|
||||
},
|
||||
res: res{
|
||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE ( aggregate_type = $1 ) ORDER BY event_sequence DESC",
|
||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events AS OF SYSTEM TIME '-1 ms' WHERE ( aggregate_type = $1 ) ORDER BY event_sequence DESC",
|
||||
rowScanner: true,
|
||||
values: []interface{}{es_models.AggregateType("user")},
|
||||
},
|
||||
@ -446,7 +447,7 @@ func Test_buildQuery(t *testing.T) {
|
||||
queryFactory: es_models.NewSearchQueryFactory().Limit(5).AddQuery().AggregateTypes("user").Factory(),
|
||||
},
|
||||
res: res{
|
||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE ( aggregate_type = $1 ) ORDER BY event_sequence LIMIT $2",
|
||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events AS OF SYSTEM TIME '-1 ms' WHERE ( aggregate_type = $1 ) ORDER BY event_sequence LIMIT $2",
|
||||
rowScanner: true,
|
||||
values: []interface{}{es_models.AggregateType("user"), uint64(5)},
|
||||
limit: 5,
|
||||
@ -458,7 +459,7 @@ func Test_buildQuery(t *testing.T) {
|
||||
queryFactory: es_models.NewSearchQueryFactory().Limit(5).OrderDesc().AddQuery().AggregateTypes("user").Factory(),
|
||||
},
|
||||
res: res{
|
||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events WHERE ( aggregate_type = $1 ) ORDER BY event_sequence DESC LIMIT $2",
|
||||
query: "SELECT creation_date, event_type, event_sequence, previous_aggregate_sequence, event_data, editor_service, editor_user, resource_owner, instance_id, aggregate_type, aggregate_id, aggregate_version FROM eventstore.events AS OF SYSTEM TIME '-1 ms' WHERE ( aggregate_type = $1 ) ORDER BY event_sequence DESC LIMIT $2",
|
||||
rowScanner: true,
|
||||
values: []interface{}{es_models.AggregateType("user"), uint64(5)},
|
||||
limit: 5,
|
||||
@ -466,8 +467,10 @@ func Test_buildQuery(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
ctx := context.Background()
|
||||
db := new(testDB)
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotQuery, gotLimit, gotValues, gotRowScanner := buildQuery(tt.args.queryFactory)
|
||||
gotQuery, gotLimit, gotValues, gotRowScanner := buildQuery(ctx, db, tt.args.queryFactory)
|
||||
if gotQuery != tt.res.query {
|
||||
t.Errorf("buildQuery() gotQuery = %v, want %v", gotQuery, tt.res.query)
|
||||
}
|
||||
@ -489,3 +492,13 @@ func Test_buildQuery(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type testDB struct{}
|
||||
|
||||
func (_ *testDB) Timetravel(time.Duration) string { return " AS OF SYSTEM TIME '-1 ms' " }
|
||||
|
||||
func (*testDB) DatabaseName() string { return "db" }
|
||||
|
||||
func (*testDB) Username() string { return "user" }
|
||||
|
||||
func (*testDB) Type() string { return "type" }
|
||||
|
@ -2,11 +2,12 @@ package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
)
|
||||
|
||||
type SQL struct {
|
||||
client *sql.DB
|
||||
client *database.DB
|
||||
}
|
||||
|
||||
func (db *SQL) Health(ctx context.Context) error {
|
||||
|
@ -2,7 +2,6 @@ package access
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -12,7 +11,9 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
zitadel_http "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/logstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/quota"
|
||||
@ -36,10 +37,10 @@ var _ logstore.UsageQuerier = (*databaseLogStorage)(nil)
|
||||
var _ logstore.LogCleanupper = (*databaseLogStorage)(nil)
|
||||
|
||||
type databaseLogStorage struct {
|
||||
dbClient *sql.DB
|
||||
dbClient *database.DB
|
||||
}
|
||||
|
||||
func NewDatabaseLogStorage(dbClient *sql.DB) *databaseLogStorage {
|
||||
func NewDatabaseLogStorage(dbClient *database.DB) *databaseLogStorage {
|
||||
return &databaseLogStorage{dbClient: dbClient}
|
||||
}
|
||||
|
||||
@ -98,12 +99,11 @@ func (l *databaseLogStorage) Emit(ctx context.Context, bulk []logstore.LogRecord
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: AS OF SYSTEM TIME
|
||||
func (l *databaseLogStorage) QueryUsage(ctx context.Context, instanceId string, start time.Time) (uint64, error) {
|
||||
stmt, args, err := squirrel.Select(
|
||||
fmt.Sprintf("count(%s)", accessInstanceIdCol),
|
||||
).
|
||||
From(accessLogsTable).
|
||||
From(accessLogsTable + l.dbClient.Timetravel(call.Took(ctx))).
|
||||
Where(squirrel.And{
|
||||
squirrel.Eq{accessInstanceIdCol: instanceId},
|
||||
squirrel.GtOrEq{accessTimestampCol: start},
|
||||
|
@ -2,13 +2,14 @@ package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/logstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/quota"
|
||||
@ -29,10 +30,10 @@ var _ logstore.UsageQuerier = (*databaseLogStorage)(nil)
|
||||
var _ logstore.LogCleanupper = (*databaseLogStorage)(nil)
|
||||
|
||||
type databaseLogStorage struct {
|
||||
dbClient *sql.DB
|
||||
dbClient *database.DB
|
||||
}
|
||||
|
||||
func NewDatabaseLogStorage(dbClient *sql.DB) *databaseLogStorage {
|
||||
func NewDatabaseLogStorage(dbClient *database.DB) *databaseLogStorage {
|
||||
return &databaseLogStorage{dbClient: dbClient}
|
||||
}
|
||||
|
||||
@ -91,12 +92,11 @@ func (l *databaseLogStorage) Emit(ctx context.Context, bulk []logstore.LogRecord
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: AS OF SYSTEM TIME
|
||||
func (l *databaseLogStorage) QueryUsage(ctx context.Context, instanceId string, start time.Time) (uint64, error) {
|
||||
stmt, args, err := squirrel.Select(
|
||||
fmt.Sprintf("COALESCE(SUM(%s)::INT,0)", executionTookCol),
|
||||
).
|
||||
From(executionLogsTable).
|
||||
From(executionLogsTable + l.dbClient.Timetravel(call.Took(ctx))).
|
||||
Where(squirrel.And{
|
||||
squirrel.Eq{executionInstanceIdCol: instanceId},
|
||||
squirrel.GtOrEq{executionTimestampCol: start},
|
||||
|
@ -7,9 +7,12 @@ import (
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/repository/quota"
|
||||
)
|
||||
|
||||
const handleThresholdTimeout = time.Minute
|
||||
|
||||
type QuotaQuerier interface {
|
||||
GetCurrentQuotaPeriod(ctx context.Context, instanceID string, unit quota.Unit) (config *quota.AddedEvent, periodStart time.Time, err error)
|
||||
GetDueQuotaNotifications(ctx context.Context, config *quota.AddedEvent, periodStart time.Time, used uint64) ([]*quota.NotifiedEvent, error)
|
||||
@ -94,17 +97,29 @@ func (s *Service) Limit(ctx context.Context, instanceID string) *uint64 {
|
||||
return nil
|
||||
}
|
||||
|
||||
go s.handleThresholds(ctx, quota, periodStart, usage)
|
||||
|
||||
var remaining *uint64
|
||||
if quota.Limit {
|
||||
r := uint64(math.Max(0, float64(quota.Amount)-float64(usage)))
|
||||
remaining = &r
|
||||
}
|
||||
|
||||
notifications, err := s.quotaQuerier.GetDueQuotaNotifications(ctx, quota, periodStart, usage)
|
||||
if err != nil {
|
||||
return remaining
|
||||
}
|
||||
|
||||
err = s.usageReporter.Report(ctx, notifications)
|
||||
return remaining
|
||||
}
|
||||
|
||||
func (s *Service) handleThresholds(ctx context.Context, quota *quota.AddedEvent, periodStart time.Time, usage uint64) {
|
||||
var err error
|
||||
defer func() {
|
||||
logging.OnError(err).Warn("handling quota thresholds failed")
|
||||
}()
|
||||
|
||||
detatchedCtx, cancel := context.WithTimeout(authz.Detach(ctx), handleThresholdTimeout)
|
||||
defer cancel()
|
||||
|
||||
notifications, err := s.quotaQuerier.GetDueQuotaNotifications(detatchedCtx, quota, periodStart, usage)
|
||||
if err != nil || len(notifications) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
err = s.usageReporter.Report(detatchedCtx, notifications)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -117,7 +118,7 @@ func (q *Queries) SearchActions(ctx context.Context, queries *ActionSearchQuerie
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareActionsQuery()
|
||||
query, scan := prepareActionsQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
ActionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}
|
||||
@ -145,7 +146,7 @@ func (q *Queries) GetActionByID(ctx context.Context, id string, orgID string, wi
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareActionQuery()
|
||||
stmt, scan := prepareActionQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
ActionColumnID.identifier(): id,
|
||||
ActionColumnResourceOwner.identifier(): orgID,
|
||||
@ -179,7 +180,7 @@ func NewActionIDSearchQuery(id string) (SearchQuery, error) {
|
||||
return NewTextQuery(ActionColumnID, id, TextEquals)
|
||||
}
|
||||
|
||||
func prepareActionsQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*Actions, error)) {
|
||||
func prepareActionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*Actions, error)) {
|
||||
return sq.Select(
|
||||
ActionColumnID.identifier(),
|
||||
ActionColumnCreationDate.identifier(),
|
||||
@ -192,7 +193,8 @@ func prepareActionsQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*Actions, er
|
||||
ActionColumnTimeout.identifier(),
|
||||
ActionColumnAllowedToFail.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(actionTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
).From(actionTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*Actions, error) {
|
||||
actions := make([]*Action, 0)
|
||||
var count uint64
|
||||
@ -230,7 +232,7 @@ func prepareActionsQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*Actions, er
|
||||
}
|
||||
}
|
||||
|
||||
func prepareActionQuery() (sq.SelectBuilder, func(row *sql.Row) (*Action, error)) {
|
||||
func prepareActionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(row *sql.Row) (*Action, error)) {
|
||||
return sq.Select(
|
||||
ActionColumnID.identifier(),
|
||||
ActionColumnCreationDate.identifier(),
|
||||
@ -242,7 +244,8 @@ func prepareActionQuery() (sq.SelectBuilder, func(row *sql.Row) (*Action, error)
|
||||
ActionColumnScript.identifier(),
|
||||
ActionColumnTimeout.identifier(),
|
||||
ActionColumnAllowedToFail.identifier(),
|
||||
).From(actionTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
).From(actionTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*Action, error) {
|
||||
action := new(Action)
|
||||
err := row.Scan(
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -70,7 +71,7 @@ func (q *Queries) GetFlow(ctx context.Context, flowType domain.FlowType, orgID s
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareFlowQuery(flowType)
|
||||
query, scan := prepareFlowQuery(ctx, q.client, flowType)
|
||||
eq := sq.Eq{
|
||||
FlowsTriggersColumnFlowType.identifier(): flowType,
|
||||
FlowsTriggersColumnResourceOwner.identifier(): orgID,
|
||||
@ -95,7 +96,7 @@ func (q *Queries) GetActiveActionsByFlowAndTriggerType(ctx context.Context, flow
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareTriggerActionsQuery()
|
||||
stmt, scan := prepareTriggerActionsQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
FlowsTriggersColumnFlowType.identifier(): flowType,
|
||||
FlowsTriggersColumnTriggerType.identifier(): triggerType,
|
||||
@ -122,7 +123,7 @@ func (q *Queries) GetFlowTypesOfActionID(ctx context.Context, actionID string, w
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareFlowTypesQuery()
|
||||
stmt, scan := prepareFlowTypesQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
FlowsTriggersColumnActionID.identifier(): actionID,
|
||||
FlowsTriggersColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -143,11 +144,11 @@ func (q *Queries) GetFlowTypesOfActionID(ctx context.Context, actionID string, w
|
||||
return scan(rows)
|
||||
}
|
||||
|
||||
func prepareFlowTypesQuery() (sq.SelectBuilder, func(*sql.Rows) ([]domain.FlowType, error)) {
|
||||
func prepareFlowTypesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) ([]domain.FlowType, error)) {
|
||||
return sq.Select(
|
||||
FlowsTriggersColumnFlowType.identifier(),
|
||||
).
|
||||
From(flowsTriggersTable.identifier()).
|
||||
From(flowsTriggersTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) ([]domain.FlowType, error) {
|
||||
types := []domain.FlowType{}
|
||||
@ -166,7 +167,7 @@ func prepareFlowTypesQuery() (sq.SelectBuilder, func(*sql.Rows) ([]domain.FlowTy
|
||||
|
||||
}
|
||||
|
||||
func prepareTriggerActionsQuery() (sq.SelectBuilder, func(*sql.Rows) ([]*Action, error)) {
|
||||
func prepareTriggerActionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) ([]*Action, error)) {
|
||||
return sq.Select(
|
||||
ActionColumnID.identifier(),
|
||||
ActionColumnCreationDate.identifier(),
|
||||
@ -180,7 +181,7 @@ func prepareTriggerActionsQuery() (sq.SelectBuilder, func(*sql.Rows) ([]*Action,
|
||||
ActionColumnTimeout.identifier(),
|
||||
).
|
||||
From(flowsTriggersTable.name).
|
||||
LeftJoin(join(ActionColumnID, FlowsTriggersColumnActionID)).
|
||||
LeftJoin(join(ActionColumnID, FlowsTriggersColumnActionID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) ([]*Action, error) {
|
||||
actions := make([]*Action, 0)
|
||||
@ -212,7 +213,7 @@ func prepareTriggerActionsQuery() (sq.SelectBuilder, func(*sql.Rows) ([]*Action,
|
||||
}
|
||||
}
|
||||
|
||||
func prepareFlowQuery(flowType domain.FlowType) (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
func prepareFlowQuery(ctx context.Context, db prepareDatabase, flowType domain.FlowType) (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return sq.Select(
|
||||
ActionColumnID.identifier(),
|
||||
ActionColumnCreationDate.identifier(),
|
||||
@ -232,7 +233,7 @@ func prepareFlowQuery(flowType domain.FlowType) (sq.SelectBuilder, func(*sql.Row
|
||||
FlowsTriggersColumnResourceOwner.identifier(),
|
||||
).
|
||||
From(flowsTriggersTable.name).
|
||||
LeftJoin(join(ActionColumnID, FlowsTriggersColumnActionID)).
|
||||
LeftJoin(join(ActionColumnID, FlowsTriggersColumnActionID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*Flow, error) {
|
||||
flow := &Flow{
|
||||
|
@ -1,6 +1,7 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
@ -14,6 +15,82 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareFlowStmt = `SELECT projections.actions3.id,` +
|
||||
` projections.actions3.creation_date,` +
|
||||
` projections.actions3.change_date,` +
|
||||
` projections.actions3.resource_owner,` +
|
||||
` projections.actions3.action_state,` +
|
||||
` projections.actions3.sequence,` +
|
||||
` projections.actions3.name,` +
|
||||
` projections.actions3.script,` +
|
||||
` projections.actions3.allowed_to_fail,` +
|
||||
` projections.actions3.timeout,` +
|
||||
` projections.flow_triggers2.trigger_type,` +
|
||||
` projections.flow_triggers2.trigger_sequence,` +
|
||||
` projections.flow_triggers2.flow_type,` +
|
||||
` projections.flow_triggers2.change_date,` +
|
||||
` projections.flow_triggers2.sequence,` +
|
||||
` projections.flow_triggers2.resource_owner` +
|
||||
` FROM projections.flow_triggers2` +
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id AND projections.flow_triggers2.instance_id = projections.actions3.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareFlowCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
"allowed_to_fail",
|
||||
"timeout",
|
||||
// flow
|
||||
"trigger_type",
|
||||
"trigger_sequence",
|
||||
"flow_type",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
}
|
||||
|
||||
prepareTriggerActionStmt = `SELECT projections.actions3.id,` +
|
||||
` projections.actions3.creation_date,` +
|
||||
` projections.actions3.change_date,` +
|
||||
` projections.actions3.resource_owner,` +
|
||||
` projections.actions3.action_state,` +
|
||||
` projections.actions3.sequence,` +
|
||||
` projections.actions3.name,` +
|
||||
` projections.actions3.script,` +
|
||||
` projections.actions3.allowed_to_fail,` +
|
||||
` projections.actions3.timeout` +
|
||||
` FROM projections.flow_triggers2` +
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id AND projections.flow_triggers2.instance_id = projections.actions3.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
|
||||
prepareTriggerActionCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
"allowed_to_fail",
|
||||
"timeout",
|
||||
}
|
||||
|
||||
prepareFlowTypeStmt = `SELECT projections.flow_triggers2.flow_type` +
|
||||
` FROM projections.flow_triggers2` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
|
||||
prepareFlowTypeCols = []string{
|
||||
"flow_type",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_FlowPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -27,29 +104,12 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "prepareFlowQuery no result",
|
||||
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(domain.FlowTypeExternalAuthentication)
|
||||
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(ctx, db, domain.FlowTypeExternalAuthentication)
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.flow_triggers2.trigger_type,`+
|
||||
` projections.flow_triggers2.trigger_sequence,`+
|
||||
` projections.flow_triggers2.flow_type,`+
|
||||
` projections.flow_triggers2.change_date,`+
|
||||
` projections.flow_triggers2.sequence,`+
|
||||
` projections.flow_triggers2.resource_owner`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
regexp.QuoteMeta(prepareFlowStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -61,48 +121,13 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "prepareFlowQuery one action",
|
||||
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(domain.FlowTypeExternalAuthentication)
|
||||
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(ctx, db, domain.FlowTypeExternalAuthentication)
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.flow_triggers2.trigger_type,`+
|
||||
` projections.flow_triggers2.trigger_sequence,`+
|
||||
` projections.flow_triggers2.flow_type,`+
|
||||
` projections.flow_triggers2.change_date,`+
|
||||
` projections.flow_triggers2.sequence,`+
|
||||
` projections.flow_triggers2.resource_owner`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
"allowed_to_fail",
|
||||
"timeout",
|
||||
//flow
|
||||
"trigger_type",
|
||||
"trigger_sequence",
|
||||
"flow_type",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
},
|
||||
regexp.QuoteMeta(prepareFlowStmt),
|
||||
prepareFlowCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"action-id",
|
||||
@ -150,48 +175,13 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "prepareFlowQuery multiple actions",
|
||||
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(domain.FlowTypeExternalAuthentication)
|
||||
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(ctx, db, domain.FlowTypeExternalAuthentication)
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.flow_triggers2.trigger_type,`+
|
||||
` projections.flow_triggers2.trigger_sequence,`+
|
||||
` projections.flow_triggers2.flow_type,`+
|
||||
` projections.flow_triggers2.change_date,`+
|
||||
` projections.flow_triggers2.sequence,`+
|
||||
` projections.flow_triggers2.resource_owner`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
"allowed_to_fail",
|
||||
"timeout",
|
||||
//flow
|
||||
"trigger_type",
|
||||
"trigger_sequence",
|
||||
"flow_type",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
},
|
||||
regexp.QuoteMeta(prepareFlowStmt),
|
||||
prepareFlowCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"action-id-pre",
|
||||
@ -271,48 +261,13 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "prepareFlowQuery no action",
|
||||
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(domain.FlowTypeExternalAuthentication)
|
||||
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(ctx, db, domain.FlowTypeExternalAuthentication)
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.flow_triggers2.trigger_type,`+
|
||||
` projections.flow_triggers2.trigger_sequence,`+
|
||||
` projections.flow_triggers2.flow_type,`+
|
||||
` projections.flow_triggers2.change_date,`+
|
||||
` projections.flow_triggers2.sequence,`+
|
||||
` projections.flow_triggers2.resource_owner`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
"allowed_to_fail",
|
||||
"timeout",
|
||||
//flow
|
||||
"trigger_type",
|
||||
"trigger_sequence",
|
||||
"flow_type",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
},
|
||||
regexp.QuoteMeta(prepareFlowStmt),
|
||||
prepareFlowCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
nil,
|
||||
@ -345,29 +300,12 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "prepareFlowQuery sql err",
|
||||
prepare: func() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(domain.FlowTypeExternalAuthentication)
|
||||
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
return prepareFlowQuery(ctx, db, domain.FlowTypeExternalAuthentication)
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.flow_triggers2.trigger_type,`+
|
||||
` projections.flow_triggers2.trigger_sequence,`+
|
||||
` projections.flow_triggers2.flow_type,`+
|
||||
` projections.flow_triggers2.change_date,`+
|
||||
` projections.flow_triggers2.sequence,`+
|
||||
` projections.flow_triggers2.resource_owner`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
regexp.QuoteMeta(prepareFlowStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -384,18 +322,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
regexp.QuoteMeta(prepareTriggerActionStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -407,30 +334,8 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
"allowed_to_fail",
|
||||
"timeout",
|
||||
},
|
||||
regexp.QuoteMeta(prepareTriggerActionStmt),
|
||||
prepareTriggerActionCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"action-id",
|
||||
@ -467,30 +372,8 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
"allowed_to_fail",
|
||||
"timeout",
|
||||
},
|
||||
regexp.QuoteMeta(prepareTriggerActionStmt),
|
||||
prepareTriggerActionCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"action-id-1",
|
||||
@ -551,18 +434,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` projections.actions3.timeout`+
|
||||
` FROM projections.flow_triggers2`+
|
||||
` LEFT JOIN projections.actions3 ON projections.flow_triggers2.action_id = projections.actions3.id`),
|
||||
regexp.QuoteMeta(prepareTriggerActionStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -579,8 +451,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareFlowTypesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+
|
||||
` FROM projections.flow_triggers2`),
|
||||
regexp.QuoteMeta(prepareFlowTypeStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -592,11 +463,8 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareFlowTypesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+
|
||||
` FROM projections.flow_triggers2`),
|
||||
[]string{
|
||||
"flow_type",
|
||||
},
|
||||
regexp.QuoteMeta(prepareFlowTypeStmt),
|
||||
prepareFlowTypeCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
domain.FlowTypeExternalAuthentication,
|
||||
@ -613,11 +481,8 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareFlowTypesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+
|
||||
` FROM projections.flow_triggers2`),
|
||||
[]string{
|
||||
"flow_type",
|
||||
},
|
||||
regexp.QuoteMeta(prepareFlowTypeStmt),
|
||||
prepareFlowTypeCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
domain.FlowTypeExternalAuthentication,
|
||||
@ -638,8 +503,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareFlowTypesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.flow_triggers2.flow_type`+
|
||||
` FROM projections.flow_triggers2`),
|
||||
regexp.QuoteMeta(prepareFlowTypeStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -654,7 +518,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,60 @@ import (
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareActionsStmt = `SELECT projections.actions3.id,` +
|
||||
` projections.actions3.creation_date,` +
|
||||
` projections.actions3.change_date,` +
|
||||
` projections.actions3.resource_owner,` +
|
||||
` projections.actions3.sequence,` +
|
||||
` projections.actions3.action_state,` +
|
||||
` projections.actions3.name,` +
|
||||
` projections.actions3.script,` +
|
||||
` projections.actions3.timeout,` +
|
||||
` projections.actions3.allowed_to_fail,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.actions3` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareActionsCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"action_state",
|
||||
"name",
|
||||
"script",
|
||||
"timeout",
|
||||
"allowed_to_fail",
|
||||
"count",
|
||||
}
|
||||
|
||||
prepareActionStmt = `SELECT projections.actions3.id,` +
|
||||
` projections.actions3.creation_date,` +
|
||||
` projections.actions3.change_date,` +
|
||||
` projections.actions3.resource_owner,` +
|
||||
` projections.actions3.sequence,` +
|
||||
` projections.actions3.action_state,` +
|
||||
` projections.actions3.name,` +
|
||||
` projections.actions3.script,` +
|
||||
` projections.actions3.timeout,` +
|
||||
` projections.actions3.allowed_to_fail` +
|
||||
` FROM projections.actions3` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareActionCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"action_state",
|
||||
"name",
|
||||
"script",
|
||||
"timeout",
|
||||
"allowed_to_fail",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_ActionPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -29,18 +83,7 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions3`),
|
||||
regexp.QuoteMeta(prepareActionsStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -52,31 +95,8 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions3`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"action_state",
|
||||
"name",
|
||||
"script",
|
||||
"timeout",
|
||||
"allowed_to_fail",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareActionsStmt),
|
||||
prepareActionsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"id",
|
||||
@ -118,31 +138,8 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions3`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"action_state",
|
||||
"name",
|
||||
"script",
|
||||
"timeout",
|
||||
"allowed_to_fail",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareActionsStmt),
|
||||
prepareActionsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"id-1",
|
||||
@ -208,18 +205,7 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.actions3.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions3`),
|
||||
regexp.QuoteMeta(prepareActionsStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -236,17 +222,7 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.actions3.allowed_to_fail`+
|
||||
` FROM projections.actions3`),
|
||||
regexp.QuoteMeta(prepareActionStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -264,29 +240,8 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.actions3.allowed_to_fail`+
|
||||
` FROM projections.actions3`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"action_state",
|
||||
"name",
|
||||
"script",
|
||||
"timeout",
|
||||
"allowed_to_fail",
|
||||
},
|
||||
regexp.QuoteMeta(prepareActionStmt),
|
||||
prepareActionCols,
|
||||
[]driver.Value{
|
||||
"id",
|
||||
testNow,
|
||||
@ -319,17 +274,7 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions3.id,`+
|
||||
` projections.actions3.creation_date,`+
|
||||
` projections.actions3.change_date,`+
|
||||
` projections.actions3.resource_owner,`+
|
||||
` projections.actions3.sequence,`+
|
||||
` projections.actions3.action_state,`+
|
||||
` projections.actions3.name,`+
|
||||
` projections.actions3.script,`+
|
||||
` projections.actions3.timeout,`+
|
||||
` projections.actions3.allowed_to_fail`+
|
||||
` FROM projections.actions3`),
|
||||
regexp.QuoteMeta(prepareActionStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -344,7 +289,7 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
@ -250,7 +251,7 @@ func (q *Queries) AppByProjectAndAppID(ctx context.Context, shouldTriggerBulk bo
|
||||
projection.AppProjection.Trigger(ctx)
|
||||
}
|
||||
|
||||
stmt, scan := prepareAppQuery()
|
||||
stmt, scan := prepareAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
AppColumnID.identifier(): appID,
|
||||
AppColumnProjectID.identifier(): projectID,
|
||||
@ -272,7 +273,7 @@ func (q *Queries) AppByID(ctx context.Context, appID string, withOwnerRemoved bo
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareAppQuery()
|
||||
stmt, scan := prepareAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
AppColumnID.identifier(): appID,
|
||||
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -293,7 +294,7 @@ func (q *Queries) AppBySAMLEntityID(ctx context.Context, entityID string, withOw
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareAppQuery()
|
||||
stmt, scan := prepareAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
AppSAMLConfigColumnEntityID.identifier(): entityID,
|
||||
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -314,7 +315,7 @@ func (q *Queries) ProjectByClientID(ctx context.Context, appID string, withOwner
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareProjectByAppQuery()
|
||||
stmt, scan := prepareProjectByAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
if !withOwnerRemoved {
|
||||
eq[ProjectColumnOwnerRemoved.identifier()] = false
|
||||
@ -339,7 +340,7 @@ func (q *Queries) ProjectIDFromOIDCClientID(ctx context.Context, appID string, w
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareProjectIDByAppQuery()
|
||||
stmt, scan := prepareProjectIDByAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
AppOIDCConfigColumnClientID.identifier(): appID,
|
||||
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -360,7 +361,7 @@ func (q *Queries) ProjectIDFromClientID(ctx context.Context, appID string, withO
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareProjectIDByAppQuery()
|
||||
stmt, scan := prepareProjectIDByAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
if !withOwnerRemoved {
|
||||
eq[AppColumnOwnerRemoved.identifier()] = false
|
||||
@ -386,7 +387,7 @@ func (q *Queries) ProjectByOIDCClientID(ctx context.Context, id string, withOwne
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareProjectByAppQuery()
|
||||
stmt, scan := prepareProjectByAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
AppOIDCConfigColumnClientID.identifier(): id,
|
||||
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -407,7 +408,7 @@ func (q *Queries) AppByOIDCClientID(ctx context.Context, clientID string, withOw
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareAppQuery()
|
||||
stmt, scan := prepareAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
AppOIDCConfigColumnClientID.identifier(): clientID,
|
||||
AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -428,7 +429,7 @@ func (q *Queries) AppByClientID(ctx context.Context, clientID string, withOwnerR
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareAppQuery()
|
||||
stmt, scan := prepareAppQuery(ctx, q.client)
|
||||
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
if !withOwnerRemoved {
|
||||
eq[AppColumnOwnerRemoved.identifier()] = false
|
||||
@ -452,7 +453,7 @@ func (q *Queries) SearchApps(ctx context.Context, queries *AppSearchQueries, wit
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareAppsQuery()
|
||||
query, scan := prepareAppsQuery(ctx, q.client)
|
||||
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
if !withOwnerRemoved {
|
||||
eq[AppColumnOwnerRemoved.identifier()] = false
|
||||
@ -478,7 +479,7 @@ func (q *Queries) SearchClientIDs(ctx context.Context, queries *AppSearchQueries
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareClientIDsQuery()
|
||||
query, scan := prepareClientIDsQuery(ctx, q.client)
|
||||
eq := sq.Eq{AppColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
if !withOwnerRemoved {
|
||||
eq[AppColumnOwnerRemoved.identifier()] = false
|
||||
@ -503,7 +504,7 @@ func NewAppProjectIDSearchQuery(id string) (SearchQuery, error) {
|
||||
return NewTextQuery(AppColumnProjectID, id, TextEquals)
|
||||
}
|
||||
|
||||
func prepareAppQuery() (sq.SelectBuilder, func(*sql.Row) (*App, error)) {
|
||||
func prepareAppQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*App, error)) {
|
||||
return sq.Select(
|
||||
AppColumnID.identifier(),
|
||||
AppColumnName.identifier(),
|
||||
@ -542,7 +543,7 @@ func prepareAppQuery() (sq.SelectBuilder, func(*sql.Row) (*App, error)) {
|
||||
).From(appsTable.identifier()).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar), func(row *sql.Row) (*App, error) {
|
||||
app := new(App)
|
||||
|
||||
@ -604,13 +605,13 @@ func prepareAppQuery() (sq.SelectBuilder, func(*sql.Row) (*App, error)) {
|
||||
}
|
||||
}
|
||||
|
||||
func prepareProjectIDByAppQuery() (sq.SelectBuilder, func(*sql.Row) (projectID string, err error)) {
|
||||
func prepareProjectIDByAppQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (projectID string, err error)) {
|
||||
return sq.Select(
|
||||
AppColumnProjectID.identifier(),
|
||||
).From(appsTable.identifier()).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar), func(row *sql.Row) (projectID string, err error) {
|
||||
err = row.Scan(
|
||||
&projectID,
|
||||
@ -627,7 +628,7 @@ func prepareProjectIDByAppQuery() (sq.SelectBuilder, func(*sql.Row) (projectID s
|
||||
}
|
||||
}
|
||||
|
||||
func prepareProjectByAppQuery() (sq.SelectBuilder, func(*sql.Row) (*Project, error)) {
|
||||
func prepareProjectByAppQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*Project, error)) {
|
||||
return sq.Select(
|
||||
ProjectColumnID.identifier(),
|
||||
ProjectColumnCreationDate.identifier(),
|
||||
@ -644,7 +645,7 @@ func prepareProjectByAppQuery() (sq.SelectBuilder, func(*sql.Row) (*Project, err
|
||||
Join(join(AppColumnProjectID, ProjectColumnID)).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*Project, error) {
|
||||
p := new(Project)
|
||||
@ -671,7 +672,7 @@ func prepareProjectByAppQuery() (sq.SelectBuilder, func(*sql.Row) (*Project, err
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAppsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
func prepareAppsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
return sq.Select(
|
||||
AppColumnID.identifier(),
|
||||
AppColumnName.identifier(),
|
||||
@ -711,7 +712,7 @@ func prepareAppsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
).From(appsTable.identifier()).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppSAMLConfigColumnAppID, AppColumnID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar), func(row *sql.Rows) (*Apps, error) {
|
||||
apps := &Apps{Apps: []*App{}}
|
||||
|
||||
@ -777,13 +778,13 @@ func prepareAppsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Apps, error)) {
|
||||
}
|
||||
}
|
||||
|
||||
func prepareClientIDsQuery() (sq.SelectBuilder, func(*sql.Rows) ([]string, error)) {
|
||||
func prepareClientIDsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) ([]string, error)) {
|
||||
return sq.Select(
|
||||
AppAPIConfigColumnClientID.identifier(),
|
||||
AppOIDCConfigColumnClientID.identifier(),
|
||||
).From(appsTable.identifier()).
|
||||
LeftJoin(join(AppAPIConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID)).
|
||||
LeftJoin(join(AppOIDCConfigColumnAppID, AppColumnID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar), func(rows *sql.Rows) ([]string, error) {
|
||||
ids := database.StringArray{}
|
||||
|
||||
|
@ -52,7 +52,8 @@ var (
|
||||
` FROM projections.apps4` +
|
||||
` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`)
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps4.id,` +
|
||||
` projections.apps4.name,` +
|
||||
` projections.apps4.project_id,` +
|
||||
@ -91,17 +92,20 @@ var (
|
||||
` FROM projections.apps4` +
|
||||
` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`)
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps4_api_configs.client_id,` +
|
||||
` projections.apps4_oidc_configs.client_id` +
|
||||
` FROM projections.apps4` +
|
||||
` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id`)
|
||||
` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps4.project_id` +
|
||||
` FROM projections.apps4` +
|
||||
` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`)
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
expectedProjectByAppQuery = regexp.QuoteMeta(`SELECT projections.projects3.id,` +
|
||||
` projections.projects3.creation_date,` +
|
||||
` projections.projects3.change_date,` +
|
||||
@ -117,7 +121,8 @@ var (
|
||||
` JOIN projections.apps4 ON projections.projects3.id = projections.apps4.project_id AND projections.projects3.instance_id = projections.apps4.instance_id` +
|
||||
` LEFT JOIN projections.apps4_api_configs ON projections.apps4.id = projections.apps4_api_configs.app_id AND projections.apps4.instance_id = projections.apps4_api_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_oidc_configs ON projections.apps4.id = projections.apps4_oidc_configs.app_id AND projections.apps4.instance_id = projections.apps4_oidc_configs.instance_id` +
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id`)
|
||||
` LEFT JOIN projections.apps4_saml_configs ON projections.apps4.id = projections.apps4_saml_configs.app_id AND projections.apps4.instance_id = projections.apps4_saml_configs.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
|
||||
appCols = database.StringArray{
|
||||
"id",
|
||||
@ -1009,7 +1014,7 @@ func Test_AppsPrepare(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1628,7 +1633,7 @@ func Test_AppPrepare(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1714,7 +1719,7 @@ func Test_AppIDsPrepare(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1780,7 +1785,7 @@ func Test_ProjectIDByAppPrepare(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1978,7 +1983,7 @@ func Test_ProjectByAppPrepare(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -129,7 +130,7 @@ func (q *Queries) SearchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQu
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareAuthNKeysQuery()
|
||||
query, scan := prepareAuthNKeysQuery(ctx, q.client)
|
||||
query = queries.toQuery(query)
|
||||
eq := sq.Eq{
|
||||
AuthNKeyColumnEnabled.identifier(): true,
|
||||
@ -159,7 +160,7 @@ func (q *Queries) SearchAuthNKeysData(ctx context.Context, queries *AuthNKeySear
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareAuthNKeysDataQuery()
|
||||
query, scan := prepareAuthNKeysDataQuery(ctx, q.client)
|
||||
query = queries.toQuery(query)
|
||||
eq := sq.Eq{
|
||||
AuthNKeyColumnEnabled.identifier(): true,
|
||||
@ -193,7 +194,7 @@ func (q *Queries) GetAuthNKeyByID(ctx context.Context, shouldTriggerBulk bool, i
|
||||
projection.AuthNKeyProjection.Trigger(ctx)
|
||||
}
|
||||
|
||||
query, scan := prepareAuthNKeyQuery()
|
||||
query, scan := prepareAuthNKeyQuery(ctx, q.client)
|
||||
for _, q := range queries {
|
||||
query = q.toQuery(query)
|
||||
}
|
||||
@ -218,7 +219,7 @@ func (q *Queries) GetAuthNKeyPublicKeyByIDAndIdentifier(ctx context.Context, id
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareAuthNKeyPublicKeyQuery()
|
||||
stmt, scan := prepareAuthNKeyPublicKeyQuery(ctx, q.client)
|
||||
eq := sq.And{
|
||||
sq.Eq{
|
||||
AuthNKeyColumnID.identifier(): id,
|
||||
@ -265,7 +266,7 @@ func NewAuthNKeyObjectIDQuery(id string) (SearchQuery, error) {
|
||||
return NewTextQuery(AuthNKeyColumnObjectID, id, TextEquals)
|
||||
}
|
||||
|
||||
func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys, error)) {
|
||||
func prepareAuthNKeysQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys, error)) {
|
||||
return sq.Select(
|
||||
AuthNKeyColumnID.identifier(),
|
||||
AuthNKeyColumnCreationDate.identifier(),
|
||||
@ -275,7 +276,8 @@ func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys
|
||||
AuthNKeyColumnExpiration.identifier(),
|
||||
AuthNKeyColumnType.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(authNKeyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
).From(authNKeyTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*AuthNKeys, error) {
|
||||
authNKeys := make([]*AuthNKey, 0)
|
||||
var count uint64
|
||||
@ -310,7 +312,7 @@ func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAuthNKeyQuery() (sq.SelectBuilder, func(row *sql.Row) (*AuthNKey, error)) {
|
||||
func prepareAuthNKeyQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(row *sql.Row) (*AuthNKey, error)) {
|
||||
return sq.Select(
|
||||
AuthNKeyColumnID.identifier(),
|
||||
AuthNKeyColumnCreationDate.identifier(),
|
||||
@ -319,7 +321,8 @@ func prepareAuthNKeyQuery() (sq.SelectBuilder, func(row *sql.Row) (*AuthNKey, er
|
||||
AuthNKeyColumnSequence.identifier(),
|
||||
AuthNKeyColumnExpiration.identifier(),
|
||||
AuthNKeyColumnType.identifier(),
|
||||
).From(authNKeyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
).From(authNKeyTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*AuthNKey, error) {
|
||||
authNKey := new(AuthNKey)
|
||||
err := row.Scan(
|
||||
@ -341,10 +344,11 @@ func prepareAuthNKeyQuery() (sq.SelectBuilder, func(row *sql.Row) (*AuthNKey, er
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAuthNKeyPublicKeyQuery() (sq.SelectBuilder, func(row *sql.Row) ([]byte, error)) {
|
||||
func prepareAuthNKeyPublicKeyQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(row *sql.Row) ([]byte, error)) {
|
||||
return sq.Select(
|
||||
AuthNKeyColumnPublicKey.identifier(),
|
||||
).From(authNKeyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
).From(authNKeyTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) ([]byte, error) {
|
||||
var publicKey []byte
|
||||
err := row.Scan(
|
||||
@ -360,7 +364,7 @@ func prepareAuthNKeyPublicKeyQuery() (sq.SelectBuilder, func(row *sql.Row) ([]by
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAuthNKeysDataQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeysData, error)) {
|
||||
func prepareAuthNKeysDataQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeysData, error)) {
|
||||
return sq.Select(
|
||||
AuthNKeyColumnID.identifier(),
|
||||
AuthNKeyColumnCreationDate.identifier(),
|
||||
@ -372,7 +376,8 @@ func prepareAuthNKeysDataQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthN
|
||||
AuthNKeyColumnIdentifier.identifier(),
|
||||
AuthNKeyColumnPublicKey.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(authNKeyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
).From(authNKeyTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*AuthNKeysData, error) {
|
||||
authNKeys := make([]*AuthNKeyData, 0)
|
||||
var count uint64
|
||||
|
@ -12,6 +12,80 @@ import (
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareAuthNKeysStmt = `SELECT projections.authn_keys2.id,` +
|
||||
` projections.authn_keys2.creation_date,` +
|
||||
` projections.authn_keys2.change_date,` +
|
||||
` projections.authn_keys2.resource_owner,` +
|
||||
` projections.authn_keys2.sequence,` +
|
||||
` projections.authn_keys2.expiration,` +
|
||||
` projections.authn_keys2.type,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.authn_keys2` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareAuthNKeysCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
"count",
|
||||
}
|
||||
|
||||
prepareAuthNKeysDataStmt = `SELECT projections.authn_keys2.id,` +
|
||||
` projections.authn_keys2.creation_date,` +
|
||||
` projections.authn_keys2.change_date,` +
|
||||
` projections.authn_keys2.resource_owner,` +
|
||||
` projections.authn_keys2.sequence,` +
|
||||
` projections.authn_keys2.expiration,` +
|
||||
` projections.authn_keys2.type,` +
|
||||
` projections.authn_keys2.identifier,` +
|
||||
` projections.authn_keys2.public_key,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.authn_keys2` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareAuthNKeysDataCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
"identifier",
|
||||
"public_key",
|
||||
"count",
|
||||
}
|
||||
|
||||
prepareAuthNKeyStmt = `SELECT projections.authn_keys2.id,` +
|
||||
` projections.authn_keys2.creation_date,` +
|
||||
` projections.authn_keys2.change_date,` +
|
||||
` projections.authn_keys2.resource_owner,` +
|
||||
` projections.authn_keys2.sequence,` +
|
||||
` projections.authn_keys2.expiration,` +
|
||||
` projections.authn_keys2.type` +
|
||||
` FROM projections.authn_keys2` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareAuthNKeyCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
}
|
||||
|
||||
prepareAuthNKeyPublicKeyStmt = `SELECT projections.authn_keys2.public_key` +
|
||||
` FROM projections.authn_keys2` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareAuthNKeyPublicKeyCols = []string{
|
||||
"public_key",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -28,15 +102,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeysStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -48,25 +114,8 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareAuthNKeysStmt),
|
||||
prepareAuthNKeysCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"id",
|
||||
@ -102,25 +151,8 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareAuthNKeysStmt),
|
||||
prepareAuthNKeysCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"id-1",
|
||||
@ -174,15 +206,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeysStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -199,17 +223,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysDataQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` projections.authn_keys2.identifier,`+
|
||||
` projections.authn_keys2.public_key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeysDataStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -221,29 +235,8 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysDataQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` projections.authn_keys2.identifier,`+
|
||||
` projections.authn_keys2.public_key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
"identifier",
|
||||
"public_key",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareAuthNKeysDataStmt),
|
||||
prepareAuthNKeysDataCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"id",
|
||||
@ -283,29 +276,8 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysDataQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` projections.authn_keys2.identifier,`+
|
||||
` projections.authn_keys2.public_key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
"identifier",
|
||||
"public_key",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareAuthNKeysDataStmt),
|
||||
prepareAuthNKeysDataCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"id-1",
|
||||
@ -367,17 +339,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeysDataQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type,`+
|
||||
` projections.authn_keys2.identifier,`+
|
||||
` projections.authn_keys2.public_key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeysDataStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -394,14 +356,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeyStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -419,23 +374,8 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type`+
|
||||
` FROM projections.authn_keys2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"sequence",
|
||||
"expiration",
|
||||
"type",
|
||||
},
|
||||
regexp.QuoteMeta(prepareAuthNKeyStmt),
|
||||
prepareAuthNKeyCols,
|
||||
[]driver.Value{
|
||||
"id",
|
||||
testNow,
|
||||
@ -462,14 +402,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.id,`+
|
||||
` projections.authn_keys2.creation_date,`+
|
||||
` projections.authn_keys2.change_date,`+
|
||||
` projections.authn_keys2.resource_owner,`+
|
||||
` projections.authn_keys2.sequence,`+
|
||||
` projections.authn_keys2.expiration,`+
|
||||
` projections.authn_keys2.type`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeyStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -486,8 +419,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeyPublicKeyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.public_key`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeyPublicKeyStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -505,11 +437,8 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeyPublicKeyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.public_key`+
|
||||
` FROM projections.authn_keys2`),
|
||||
[]string{
|
||||
"public_key",
|
||||
},
|
||||
regexp.QuoteMeta(prepareAuthNKeyPublicKeyStmt),
|
||||
prepareAuthNKeyPublicKeyCols,
|
||||
[]driver.Value{
|
||||
[]byte("publicKey"),
|
||||
},
|
||||
@ -522,8 +451,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
prepare: prepareAuthNKeyPublicKeyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.authn_keys2.public_key`+
|
||||
` FROM projections.authn_keys2`),
|
||||
regexp.QuoteMeta(prepareAuthNKeyPublicKeyStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -538,7 +466,7 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
@ -69,7 +70,7 @@ func (q *Queries) ActiveCertificates(ctx context.Context, t time.Time, usage dom
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareCertificateQuery()
|
||||
query, scan := prepareCertificateQuery(ctx, q.client)
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
}
|
||||
@ -102,7 +103,7 @@ func (q *Queries) ActiveCertificates(ctx context.Context, t time.Time, usage dom
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func prepareCertificateQuery() (sq.SelectBuilder, func(*sql.Rows) (*Certificates, error)) {
|
||||
func prepareCertificateQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Certificates, error)) {
|
||||
return sq.Select(
|
||||
KeyColID.identifier(),
|
||||
KeyColCreationDate.identifier(),
|
||||
@ -117,7 +118,7 @@ func prepareCertificateQuery() (sq.SelectBuilder, func(*sql.Rows) (*Certificates
|
||||
countColumn.identifier(),
|
||||
).From(keyTable.identifier()).
|
||||
LeftJoin(join(CertificateColID, KeyColID)).
|
||||
LeftJoin(join(KeyPrivateColID, KeyColID)).
|
||||
LeftJoin(join(KeyPrivateColID, KeyColID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*Certificates, error) {
|
||||
certificates := make([]Certificate, 0)
|
||||
|
@ -13,6 +13,37 @@ import (
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareCertificateStmt = `SELECT projections.keys4.id,` +
|
||||
` projections.keys4.creation_date,` +
|
||||
` projections.keys4.change_date,` +
|
||||
` projections.keys4.sequence,` +
|
||||
` projections.keys4.resource_owner,` +
|
||||
` projections.keys4.algorithm,` +
|
||||
` projections.keys4.use,` +
|
||||
` projections.keys4_certificate.expiry,` +
|
||||
` projections.keys4_certificate.certificate,` +
|
||||
` projections.keys4_private.key,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.keys4` +
|
||||
` LEFT JOIN projections.keys4_certificate ON projections.keys4.id = projections.keys4_certificate.id AND projections.keys4.instance_id = projections.keys4_certificate.instance_id` +
|
||||
` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareCertificateCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
"algorithm",
|
||||
"use",
|
||||
"expiry",
|
||||
"certificate",
|
||||
"key",
|
||||
"count",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_CertificatePrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -29,20 +60,7 @@ func Test_CertificatePrepares(t *testing.T) {
|
||||
prepare: prepareCertificateQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys4.id,`+
|
||||
` projections.keys4.creation_date,`+
|
||||
` projections.keys4.change_date,`+
|
||||
` projections.keys4.sequence,`+
|
||||
` projections.keys4.resource_owner,`+
|
||||
` projections.keys4.algorithm,`+
|
||||
` projections.keys4.use,`+
|
||||
` projections.keys4_certificate.expiry,`+
|
||||
` projections.keys4_certificate.certificate,`+
|
||||
` projections.keys4_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys4`+
|
||||
` LEFT JOIN projections.keys4_certificate ON projections.keys4.id = projections.keys4_certificate.id AND projections.keys4.instance_id = projections.keys4_certificate.instance_id`+
|
||||
` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id`),
|
||||
regexp.QuoteMeta(prepareCertificateStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -60,33 +78,8 @@ func Test_CertificatePrepares(t *testing.T) {
|
||||
prepare: prepareCertificateQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.keys4.id,`+
|
||||
` projections.keys4.creation_date,`+
|
||||
` projections.keys4.change_date,`+
|
||||
` projections.keys4.sequence,`+
|
||||
` projections.keys4.resource_owner,`+
|
||||
` projections.keys4.algorithm,`+
|
||||
` projections.keys4.use,`+
|
||||
` projections.keys4_certificate.expiry,`+
|
||||
` projections.keys4_certificate.certificate,`+
|
||||
` projections.keys4_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys4`+
|
||||
` LEFT JOIN projections.keys4_certificate ON projections.keys4.id = projections.keys4_certificate.id AND projections.keys4.instance_id = projections.keys4_certificate.instance_id`+
|
||||
` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
"algorithm",
|
||||
"use",
|
||||
"expiry",
|
||||
"certificate",
|
||||
"key",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareCertificateStmt),
|
||||
prepareCertificateCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"key-id",
|
||||
@ -135,20 +128,7 @@ func Test_CertificatePrepares(t *testing.T) {
|
||||
prepare: prepareCertificateQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.keys4.id,`+
|
||||
` projections.keys4.creation_date,`+
|
||||
` projections.keys4.change_date,`+
|
||||
` projections.keys4.sequence,`+
|
||||
` projections.keys4.resource_owner,`+
|
||||
` projections.keys4.algorithm,`+
|
||||
` projections.keys4.use,`+
|
||||
` projections.keys4_certificate.expiry,`+
|
||||
` projections.keys4_certificate.certificate,`+
|
||||
` projections.keys4_private.key,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.keys4`+
|
||||
` LEFT JOIN projections.keys4_certificate ON projections.keys4.id = projections.keys4_certificate.id AND projections.keys4.instance_id = projections.keys4_certificate.instance_id`+
|
||||
` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id`),
|
||||
regexp.QuoteMeta(prepareCertificateStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -163,7 +143,7 @@ func Test_CertificatePrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func (q *Queries) UserChanges(ctx context.Context, userID string, lastSequence u
|
||||
}
|
||||
|
||||
func (q *Queries) changes(ctx context.Context, query func(query *eventstore.SearchQuery), lastSequence uint64, limit uint64, sortAscending bool, auditLogRetention time.Duration) (*Changes, error) {
|
||||
builder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).Limit(limit)
|
||||
builder := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).Limit(limit).AllowTimeTravel()
|
||||
if !sortAscending {
|
||||
builder.OrderDesc()
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
@ -59,7 +60,7 @@ func (q *Queries) SearchCurrentSequences(ctx context.Context, queries *CurrentSe
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareCurrentSequencesQuery()
|
||||
query, scan := prepareCurrentSequencesQuery(ctx, q.client)
|
||||
stmt, args, err := queries.toQuery(query).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInvalidArgument(err, "QUERY-MmFef", "Errors.Query.InvalidRequest")
|
||||
@ -76,7 +77,7 @@ func (q *Queries) latestSequence(ctx context.Context, projections ...table) (_ *
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareLatestSequence()
|
||||
query, scan := prepareLatestSequence(ctx, q.client)
|
||||
or := make(sq.Or, len(projections))
|
||||
for i, projection := range projections {
|
||||
or[i] = sq.Eq{CurrentSequenceColProjectionName.identifier(): projection.name}
|
||||
@ -201,11 +202,12 @@ func reset(tx *sql.Tx, tables []string, projectionName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func prepareLatestSequence() (sq.SelectBuilder, func(*sql.Row) (*LatestSequence, error)) {
|
||||
func prepareLatestSequence(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*LatestSequence, error)) {
|
||||
return sq.Select(
|
||||
CurrentSequenceColCurrentSequence.identifier(),
|
||||
CurrentSequenceColTimestamp.identifier()).
|
||||
From(currentSequencesTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
From(currentSequencesTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*LatestSequence, error) {
|
||||
seq := new(LatestSequence)
|
||||
err := row.Scan(
|
||||
@ -219,13 +221,13 @@ func prepareLatestSequence() (sq.SelectBuilder, func(*sql.Row) (*LatestSequence,
|
||||
}
|
||||
}
|
||||
|
||||
func prepareCurrentSequencesQuery() (sq.SelectBuilder, func(*sql.Rows) (*CurrentSequences, error)) {
|
||||
func prepareCurrentSequencesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*CurrentSequences, error)) {
|
||||
return sq.Select(
|
||||
"max("+CurrentSequenceColCurrentSequence.identifier()+") as "+CurrentSequenceColCurrentSequence.name,
|
||||
"max("+CurrentSequenceColTimestamp.identifier()+") as "+CurrentSequenceColTimestamp.name,
|
||||
CurrentSequenceColProjectionName.identifier(),
|
||||
countColumn.identifier()).
|
||||
From(currentSequencesTable.identifier()).
|
||||
From(currentSequencesTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
GroupBy(CurrentSequenceColProjectionName.identifier()).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*CurrentSequences, error) {
|
||||
|
@ -9,6 +9,23 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
currentSequenceStmt = `SELECT max(projections.current_sequences.current_sequence) as current_sequence,` +
|
||||
` max(projections.current_sequences.timestamp) as timestamp,` +
|
||||
` projections.current_sequences.projection_name,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.current_sequences` +
|
||||
" AS OF SYSTEM TIME '-1 ms' " +
|
||||
` GROUP BY projections.current_sequences.projection_name`
|
||||
|
||||
currentSequenceCols = []string{
|
||||
"current_sequence",
|
||||
"timestamp",
|
||||
"projection_name",
|
||||
"count",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_CurrentSequencesPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -25,12 +42,7 @@ func Test_CurrentSequencesPrepares(t *testing.T) {
|
||||
prepare: prepareCurrentSequencesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT max(projections.current_sequences.current_sequence) as current_sequence,`+
|
||||
` max(projections.current_sequences.timestamp) as timestamp,`+
|
||||
` projections.current_sequences.projection_name,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.current_sequences`+
|
||||
` GROUP BY projections.current_sequences.projection_name`),
|
||||
regexp.QuoteMeta(currentSequenceStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -42,18 +54,8 @@ func Test_CurrentSequencesPrepares(t *testing.T) {
|
||||
prepare: prepareCurrentSequencesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT max(projections.current_sequences.current_sequence) as current_sequence,`+
|
||||
` max(projections.current_sequences.timestamp) as timestamp,`+
|
||||
` projections.current_sequences.projection_name,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.current_sequences`+
|
||||
` GROUP BY projections.current_sequences.projection_name`),
|
||||
[]string{
|
||||
"current_sequence",
|
||||
"timestamp",
|
||||
"projection_name",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(currentSequenceStmt),
|
||||
currentSequenceCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
uint64(20211108),
|
||||
@ -81,18 +83,8 @@ func Test_CurrentSequencesPrepares(t *testing.T) {
|
||||
prepare: prepareCurrentSequencesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT max(projections.current_sequences.current_sequence) as current_sequence,`+
|
||||
` max(projections.current_sequences.timestamp) as timestamp,`+
|
||||
` projections.current_sequences.projection_name,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.current_sequences`+
|
||||
` GROUP BY projections.current_sequences.projection_name`),
|
||||
[]string{
|
||||
"current_sequence",
|
||||
"timestamp",
|
||||
"projection_name",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(currentSequenceStmt),
|
||||
currentSequenceCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
uint64(20211108),
|
||||
@ -130,12 +122,7 @@ func Test_CurrentSequencesPrepares(t *testing.T) {
|
||||
prepare: prepareCurrentSequencesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT max(projections.current_sequences.current_sequence) as current_sequence,`+
|
||||
` max(projections.current_sequences.timestamp) as timestamp,`+
|
||||
` projections.current_sequences.projection_name,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.current_sequences`+
|
||||
` GROUP BY projections.current_sequences.projection_name`),
|
||||
regexp.QuoteMeta(currentSequenceStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -150,7 +137,7 @@ func Test_CurrentSequencesPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
@ -88,7 +89,7 @@ func (q *Queries) CustomTextList(ctx context.Context, aggregateID, template, lan
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareCustomTextsQuery()
|
||||
stmt, scan := prepareCustomTextsQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
CustomTextColAggregateID.identifier(): aggregateID,
|
||||
CustomTextColTemplate.identifier(): template,
|
||||
@ -119,7 +120,7 @@ func (q *Queries) CustomTextListByTemplate(ctx context.Context, aggregateID, tem
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareCustomTextsQuery()
|
||||
stmt, scan := prepareCustomTextsQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
CustomTextColAggregateID.identifier(): aggregateID,
|
||||
CustomTextColTemplate.identifier(): template,
|
||||
@ -228,7 +229,7 @@ func (q *Queries) readLoginTranslationFile(ctx context.Context, lang string) ([]
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func prepareCustomTextsQuery() (sq.SelectBuilder, func(*sql.Rows) (*CustomTexts, error)) {
|
||||
func prepareCustomTextsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*CustomTexts, error)) {
|
||||
return sq.Select(
|
||||
CustomTextColAggregateID.identifier(),
|
||||
CustomTextColSequence.identifier(),
|
||||
@ -239,7 +240,8 @@ func prepareCustomTextsQuery() (sq.SelectBuilder, func(*sql.Rows) (*CustomTexts,
|
||||
CustomTextColKey.identifier(),
|
||||
CustomTextColText.identifier(),
|
||||
countColumn.identifier()).
|
||||
From(customTextTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
From(customTextTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*CustomTexts, error) {
|
||||
customTexts := make([]*CustomText, 0)
|
||||
var count uint64
|
||||
|
@ -13,6 +13,31 @@ import (
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareCustomTextsStmt = `SELECT projections.custom_texts2.aggregate_id,` +
|
||||
` projections.custom_texts2.sequence,` +
|
||||
` projections.custom_texts2.creation_date,` +
|
||||
` projections.custom_texts2.change_date,` +
|
||||
` projections.custom_texts2.language,` +
|
||||
` projections.custom_texts2.template,` +
|
||||
` projections.custom_texts2.key,` +
|
||||
` projections.custom_texts2.text,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.custom_texts2` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareCustomTextsCols = []string{
|
||||
"aggregate_id",
|
||||
"sequence",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"language",
|
||||
"template",
|
||||
"key",
|
||||
"text",
|
||||
"count",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_CustomTextPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -29,16 +54,7 @@ func Test_CustomTextPrepares(t *testing.T) {
|
||||
prepare: prepareCustomTextsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+
|
||||
` projections.custom_texts2.sequence,`+
|
||||
` projections.custom_texts2.creation_date,`+
|
||||
` projections.custom_texts2.change_date,`+
|
||||
` projections.custom_texts2.language,`+
|
||||
` projections.custom_texts2.template,`+
|
||||
` projections.custom_texts2.key,`+
|
||||
` projections.custom_texts2.text,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.custom_texts2`),
|
||||
regexp.QuoteMeta(prepareCustomTextsStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -56,27 +72,8 @@ func Test_CustomTextPrepares(t *testing.T) {
|
||||
prepare: prepareCustomTextsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+
|
||||
` projections.custom_texts2.sequence,`+
|
||||
` projections.custom_texts2.creation_date,`+
|
||||
` projections.custom_texts2.change_date,`+
|
||||
` projections.custom_texts2.language,`+
|
||||
` projections.custom_texts2.template,`+
|
||||
` projections.custom_texts2.key,`+
|
||||
` projections.custom_texts2.text,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.custom_texts2`),
|
||||
[]string{
|
||||
"aggregate_id",
|
||||
"sequence",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"language",
|
||||
"template",
|
||||
"key",
|
||||
"text",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareCustomTextsStmt),
|
||||
prepareCustomTextsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"agg-id",
|
||||
@ -114,27 +111,8 @@ func Test_CustomTextPrepares(t *testing.T) {
|
||||
prepare: prepareCustomTextsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+
|
||||
` projections.custom_texts2.sequence,`+
|
||||
` projections.custom_texts2.creation_date,`+
|
||||
` projections.custom_texts2.change_date,`+
|
||||
` projections.custom_texts2.language,`+
|
||||
` projections.custom_texts2.template,`+
|
||||
` projections.custom_texts2.key,`+
|
||||
` projections.custom_texts2.text,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.custom_texts2`),
|
||||
[]string{
|
||||
"aggregate_id",
|
||||
"sequence",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"language",
|
||||
"template",
|
||||
"key",
|
||||
"text",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareCustomTextsStmt),
|
||||
prepareCustomTextsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"agg-id",
|
||||
@ -192,16 +170,7 @@ func Test_CustomTextPrepares(t *testing.T) {
|
||||
prepare: prepareCustomTextsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.custom_texts2.aggregate_id,`+
|
||||
` projections.custom_texts2.sequence,`+
|
||||
` projections.custom_texts2.creation_date,`+
|
||||
` projections.custom_texts2.change_date,`+
|
||||
` projections.custom_texts2.language,`+
|
||||
` projections.custom_texts2.template,`+
|
||||
` projections.custom_texts2.key,`+
|
||||
` projections.custom_texts2.text,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.custom_texts2`),
|
||||
regexp.QuoteMeta(prepareCustomTextsStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -216,7 +185,7 @@ func Test_CustomTextPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -112,7 +113,7 @@ func (q *Queries) DomainPolicyByOrg(ctx context.Context, shouldTriggerBulk bool,
|
||||
}
|
||||
}
|
||||
|
||||
stmt, scan := prepareDomainPolicyQuery()
|
||||
stmt, scan := prepareDomainPolicyQuery(ctx, q.client)
|
||||
query, args, err := stmt.Where(eq).OrderBy(DomainPolicyColIsDefault.identifier()).
|
||||
Limit(1).ToSql()
|
||||
if err != nil {
|
||||
@ -127,7 +128,7 @@ func (q *Queries) DefaultDomainPolicy(ctx context.Context) (_ *DomainPolicy, err
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareDomainPolicyQuery()
|
||||
stmt, scan := prepareDomainPolicyQuery(ctx, q.client)
|
||||
query, args, err := stmt.Where(sq.Eq{
|
||||
DomainPolicyColID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
DomainPolicyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -142,7 +143,7 @@ func (q *Queries) DefaultDomainPolicy(ctx context.Context) (_ *DomainPolicy, err
|
||||
return scan(row)
|
||||
}
|
||||
|
||||
func prepareDomainPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*DomainPolicy, error)) {
|
||||
func prepareDomainPolicyQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*DomainPolicy, error)) {
|
||||
return sq.Select(
|
||||
DomainPolicyColID.identifier(),
|
||||
DomainPolicyColSequence.identifier(),
|
||||
@ -155,7 +156,8 @@ func prepareDomainPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*DomainPolicy
|
||||
DomainPolicyColIsDefault.identifier(),
|
||||
DomainPolicyColState.identifier(),
|
||||
).
|
||||
From(domainPolicyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
From(domainPolicyTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*DomainPolicy, error) {
|
||||
policy := new(DomainPolicy)
|
||||
err := row.Scan(
|
||||
|
@ -12,6 +12,33 @@ import (
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareDomainPolicyStmt = `SELECT projections.domain_policies2.id,` +
|
||||
` projections.domain_policies2.sequence,` +
|
||||
` projections.domain_policies2.creation_date,` +
|
||||
` projections.domain_policies2.change_date,` +
|
||||
` projections.domain_policies2.resource_owner,` +
|
||||
` projections.domain_policies2.user_login_must_be_domain,` +
|
||||
` projections.domain_policies2.validate_org_domains,` +
|
||||
` projections.domain_policies2.smtp_sender_address_matches_instance_domain,` +
|
||||
` projections.domain_policies2.is_default,` +
|
||||
` projections.domain_policies2.state` +
|
||||
` FROM projections.domain_policies2` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareDomainPolicyCols = []string{
|
||||
"id",
|
||||
"sequence",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"user_login_must_be_domain",
|
||||
"validate_org_domains",
|
||||
"smtp_sender_address_matches_instance_domain",
|
||||
"is_default",
|
||||
"state",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_DomainPolicyPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -28,17 +55,7 @@ func Test_DomainPolicyPrepares(t *testing.T) {
|
||||
prepare: prepareDomainPolicyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.domain_policies2.id,`+
|
||||
` projections.domain_policies2.sequence,`+
|
||||
` projections.domain_policies2.creation_date,`+
|
||||
` projections.domain_policies2.change_date,`+
|
||||
` projections.domain_policies2.resource_owner,`+
|
||||
` projections.domain_policies2.user_login_must_be_domain,`+
|
||||
` projections.domain_policies2.validate_org_domains,`+
|
||||
` projections.domain_policies2.smtp_sender_address_matches_instance_domain,`+
|
||||
` projections.domain_policies2.is_default,`+
|
||||
` projections.domain_policies2.state`+
|
||||
` FROM projections.domain_policies2`),
|
||||
regexp.QuoteMeta(prepareDomainPolicyStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -56,29 +73,8 @@ func Test_DomainPolicyPrepares(t *testing.T) {
|
||||
prepare: prepareDomainPolicyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(`SELECT projections.domain_policies2.id,`+
|
||||
` projections.domain_policies2.sequence,`+
|
||||
` projections.domain_policies2.creation_date,`+
|
||||
` projections.domain_policies2.change_date,`+
|
||||
` projections.domain_policies2.resource_owner,`+
|
||||
` projections.domain_policies2.user_login_must_be_domain,`+
|
||||
` projections.domain_policies2.validate_org_domains,`+
|
||||
` projections.domain_policies2.smtp_sender_address_matches_instance_domain,`+
|
||||
` projections.domain_policies2.is_default,`+
|
||||
` projections.domain_policies2.state`+
|
||||
` FROM projections.domain_policies2`),
|
||||
[]string{
|
||||
"id",
|
||||
"sequence",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"user_login_must_be_domain",
|
||||
"validate_org_domains",
|
||||
"smtp_sender_address_matches_instance_domain",
|
||||
"is_default",
|
||||
"state",
|
||||
},
|
||||
regexp.QuoteMeta(prepareDomainPolicyStmt),
|
||||
prepareDomainPolicyCols,
|
||||
[]driver.Value{
|
||||
"pol-id",
|
||||
uint64(20211109),
|
||||
@ -111,17 +107,7 @@ func Test_DomainPolicyPrepares(t *testing.T) {
|
||||
prepare: prepareDomainPolicyQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.domain_policies2.id,`+
|
||||
` projections.domain_policies2.sequence,`+
|
||||
` projections.domain_policies2.creation_date,`+
|
||||
` projections.domain_policies2.change_date,`+
|
||||
` projections.domain_policies2.resource_owner,`+
|
||||
` projections.domain_policies2.user_login_must_be_domain,`+
|
||||
` projections.domain_policies2.validate_org_domains,`+
|
||||
` projections.domain_policies2.smtp_sender_address_matches_instance_domain,`+
|
||||
` projections.domain_policies2.is_default,`+
|
||||
` projections.domain_policies2.state`+
|
||||
` FROM projections.domain_policies2`),
|
||||
regexp.QuoteMeta(prepareDomainPolicyStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -136,7 +122,7 @@ func Test_DomainPolicyPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ type EventEditor struct {
|
||||
func (q *Queries) SearchEvents(ctx context.Context, query *eventstore.SearchQueryBuilder) (_ []*Event, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
events, err := q.eventstore.Filter(ctx, query)
|
||||
events, err := q.eventstore.Filter(ctx, query.AllowTimeTravel())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
)
|
||||
@ -70,7 +71,7 @@ type FailedEventSearchQueries struct {
|
||||
}
|
||||
|
||||
func (q *Queries) SearchFailedEvents(ctx context.Context, queries *FailedEventSearchQueries) (failedEvents *FailedEvents, err error) {
|
||||
query, scan := prepareFailedEventsQuery()
|
||||
query, scan := prepareFailedEventsQuery(ctx, q.client)
|
||||
stmt, args, err := queries.toQuery(query).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInvalidArgument(err, "QUERY-n8rjJ", "Errors.Query.InvalidRequest")
|
||||
@ -123,7 +124,7 @@ func (q *FailedEventSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuil
|
||||
return query
|
||||
}
|
||||
|
||||
func prepareFailedEventsQuery() (sq.SelectBuilder, func(*sql.Rows) (*FailedEvents, error)) {
|
||||
func prepareFailedEventsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*FailedEvents, error)) {
|
||||
return sq.Select(
|
||||
FailedEventsColumnProjectionName.identifier(),
|
||||
FailedEventsColumnFailedSequence.identifier(),
|
||||
@ -131,7 +132,8 @@ func prepareFailedEventsQuery() (sq.SelectBuilder, func(*sql.Rows) (*FailedEvent
|
||||
FailedEventsColumnLastFailed.identifier(),
|
||||
FailedEventsColumnError.identifier(),
|
||||
countColumn.identifier()).
|
||||
From(failedEventsTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
From(failedEventsTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*FailedEvents, error) {
|
||||
failedEvents := make([]*FailedEvent, 0)
|
||||
var count uint64
|
||||
|
@ -9,6 +9,26 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareFailedEventsStmt = `SELECT projections.failed_events.projection_name,` +
|
||||
` projections.failed_events.failed_sequence,` +
|
||||
` projections.failed_events.failure_count,` +
|
||||
` projections.failed_events.last_failed,` +
|
||||
` projections.failed_events.error,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.failed_events` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
|
||||
prepareFailedEventsCols = []string{
|
||||
"projection_name",
|
||||
"failed_sequence",
|
||||
"failure_count",
|
||||
"last_failed",
|
||||
"error",
|
||||
"count",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_FailedEventsPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -25,13 +45,7 @@ func Test_FailedEventsPrepares(t *testing.T) {
|
||||
prepare: prepareFailedEventsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.failed_events.projection_name,`+
|
||||
` projections.failed_events.failed_sequence,`+
|
||||
` projections.failed_events.failure_count,`+
|
||||
` projections.failed_events.last_failed,`+
|
||||
` projections.failed_events.error,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.failed_events`),
|
||||
regexp.QuoteMeta(prepareFailedEventsStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -43,21 +57,8 @@ func Test_FailedEventsPrepares(t *testing.T) {
|
||||
prepare: prepareFailedEventsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.failed_events.projection_name,`+
|
||||
` projections.failed_events.failed_sequence,`+
|
||||
` projections.failed_events.failure_count,`+
|
||||
` projections.failed_events.last_failed,`+
|
||||
` projections.failed_events.error,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.failed_events`),
|
||||
[]string{
|
||||
"projection_name",
|
||||
"failed_sequence",
|
||||
"failure_count",
|
||||
"last_failed",
|
||||
"error",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareFailedEventsStmt),
|
||||
prepareFailedEventsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"projection-name",
|
||||
@ -89,21 +90,8 @@ func Test_FailedEventsPrepares(t *testing.T) {
|
||||
prepare: prepareFailedEventsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.failed_events.projection_name,`+
|
||||
` projections.failed_events.failed_sequence,`+
|
||||
` projections.failed_events.failure_count,`+
|
||||
` projections.failed_events.last_failed,`+
|
||||
` projections.failed_events.error,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.failed_events`),
|
||||
[]string{
|
||||
"projection_name",
|
||||
"failed_sequence",
|
||||
"failure_count",
|
||||
"last_failed",
|
||||
"error",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareFailedEventsStmt),
|
||||
prepareFailedEventsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"projection-name",
|
||||
@ -148,13 +136,7 @@ func Test_FailedEventsPrepares(t *testing.T) {
|
||||
prepare: prepareFailedEventsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.failed_events.projection_name,`+
|
||||
` projections.failed_events.failed_sequence,`+
|
||||
` projections.failed_events.failure_count,`+
|
||||
` projections.failed_events.last_failed,`+
|
||||
` projections.failed_events.error,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.failed_events`),
|
||||
regexp.QuoteMeta(prepareFailedEventsStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -169,7 +151,7 @@ func Test_FailedEventsPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
@ -78,7 +79,7 @@ func (q *Queries) IAMMembers(ctx context.Context, queries *IAMMembersQuery, with
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareInstanceMembersQuery()
|
||||
query, scan := prepareInstanceMembersQuery(ctx, q.client)
|
||||
eq := sq.Eq{InstanceMemberInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
if !withOwnerRemoved {
|
||||
addIamMemberWithoutOwnerRemoved(eq)
|
||||
@ -106,7 +107,7 @@ func (q *Queries) IAMMembers(ctx context.Context, queries *IAMMembersQuery, with
|
||||
return members, err
|
||||
}
|
||||
|
||||
func prepareInstanceMembersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Members, error)) {
|
||||
func prepareInstanceMembersQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*Members, error)) {
|
||||
return sq.Select(
|
||||
InstanceMemberCreationDate.identifier(),
|
||||
InstanceMemberChangeDate.identifier(),
|
||||
@ -125,7 +126,7 @@ func prepareInstanceMembersQuery() (sq.SelectBuilder, func(*sql.Rows) (*Members,
|
||||
).From(instanceMemberTable.identifier()).
|
||||
LeftJoin(join(HumanUserIDCol, InstanceMemberUserID)).
|
||||
LeftJoin(join(MachineUserIDCol, InstanceMemberUserID)).
|
||||
LeftJoin(join(LoginNameUserIDCol, InstanceMemberUserID)).
|
||||
LeftJoin(join(LoginNameUserIDCol, InstanceMemberUserID) + db.Timetravel(call.Took(ctx))).
|
||||
Where(
|
||||
sq.Eq{LoginNameIsPrimaryCol.identifier(): true},
|
||||
).PlaceholderFormat(sq.Dollar),
|
||||
|
@ -34,6 +34,7 @@ var (
|
||||
"ON members.user_id = projections.users8_machines.user_id AND members.instance_id = projections.users8_machines.instance_id " +
|
||||
"LEFT JOIN projections.login_names2 " +
|
||||
"ON members.user_id = projections.login_names2.user_id AND members.instance_id = projections.login_names2.instance_id " +
|
||||
"AS OF SYSTEM TIME '-1 ms' " +
|
||||
"WHERE projections.login_names2.is_primary = $1")
|
||||
instanceMembersColumns = []string{
|
||||
"creation_date",
|
||||
@ -271,7 +272,7 @@ func Test_IAMMemberPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@ -209,7 +210,7 @@ func (q *Queries) IDPByIDAndResourceOwner(ctx context.Context, shouldTriggerBulk
|
||||
sq.Eq{IDPResourceOwnerCol.identifier(): authz.GetInstance(ctx).InstanceID()},
|
||||
},
|
||||
}
|
||||
stmt, scan := prepareIDPByIDQuery()
|
||||
stmt, scan := prepareIDPByIDQuery(ctx, q.client)
|
||||
query, args, err := stmt.Where(where).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-0gocI", "Errors.Query.SQLStatement")
|
||||
@ -224,7 +225,7 @@ func (q *Queries) IDPs(ctx context.Context, queries *IDPSearchQueries, withOwner
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareIDPsQuery()
|
||||
query, scan := prepareIDPsQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
IDPInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}
|
||||
@ -285,7 +286,7 @@ func (q *IDPSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||
return query
|
||||
}
|
||||
|
||||
func prepareIDPByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDP, error)) {
|
||||
func prepareIDPByIDQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*IDP, error)) {
|
||||
return sq.Select(
|
||||
IDPIDCol.identifier(),
|
||||
IDPResourceOwnerCol.identifier(),
|
||||
@ -313,7 +314,7 @@ func prepareIDPByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDP, error)) {
|
||||
JWTIDPColEndpoint.identifier(),
|
||||
).From(idpTable.identifier()).
|
||||
LeftJoin(join(OIDCIDPColIDPID, IDPIDCol)).
|
||||
LeftJoin(join(JWTIDPColIDPID, IDPIDCol)).
|
||||
LeftJoin(join(JWTIDPColIDPID, IDPIDCol) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*IDP, error) {
|
||||
idp := new(IDP)
|
||||
@ -393,7 +394,7 @@ func prepareIDPByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDP, error)) {
|
||||
}
|
||||
}
|
||||
|
||||
func prepareIDPsQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPs, error)) {
|
||||
func prepareIDPsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPs, error)) {
|
||||
return sq.Select(
|
||||
IDPIDCol.identifier(),
|
||||
IDPResourceOwnerCol.identifier(),
|
||||
@ -422,7 +423,7 @@ func prepareIDPsQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPs, error)) {
|
||||
countColumn.identifier(),
|
||||
).From(idpTable.identifier()).
|
||||
LeftJoin(join(OIDCIDPColIDPID, IDPIDCol)).
|
||||
LeftJoin(join(JWTIDPColIDPID, IDPIDCol)).
|
||||
LeftJoin(join(JWTIDPColIDPID, IDPIDCol) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*IDPs, error) {
|
||||
idps := make([]*IDP, 0)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -84,7 +85,7 @@ func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string,
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareIDPLoginPolicyLinksQuery()
|
||||
query, scan := prepareIDPLoginPolicyLinksQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
IDPLoginPolicyLinkResourceOwnerCol.identifier(): resourceOwner,
|
||||
IDPLoginPolicyLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -109,14 +110,15 @@ func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string,
|
||||
return idps, err
|
||||
}
|
||||
|
||||
func prepareIDPLoginPolicyLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) {
|
||||
func prepareIDPLoginPolicyLinksQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) {
|
||||
return sq.Select(
|
||||
IDPLoginPolicyLinkIDPIDCol.identifier(),
|
||||
IDPNameCol.identifier(),
|
||||
IDPTypeCol.identifier(),
|
||||
countColumn.identifier()).
|
||||
From(idpLoginPolicyLinkTable.identifier()).
|
||||
LeftJoin(join(IDPIDCol, IDPLoginPolicyLinkIDPIDCol)).PlaceholderFormat(sq.Dollar),
|
||||
LeftJoin(join(IDPIDCol, IDPLoginPolicyLinkIDPIDCol) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*IDPLoginPolicyLinks, error) {
|
||||
links := make([]*IDPLoginPolicyLink, 0)
|
||||
var count uint64
|
||||
|
@ -17,7 +17,8 @@ var (
|
||||
` projections.idps3.type,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.idp_login_policy_links4` +
|
||||
` LEFT JOIN projections.idps3 ON projections.idp_login_policy_links4.idp_id = projections.idps3.id`)
|
||||
` LEFT JOIN projections.idps3 ON projections.idp_login_policy_links4.idp_id = projections.idps3.id AND projections.idp_login_policy_links4.instance_id = projections.idps3.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
loginPolicyIDPLinksCols = []string{
|
||||
"idp_id",
|
||||
"name",
|
||||
@ -115,7 +116,7 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@ -409,7 +410,7 @@ func (q *Queries) IDPTemplateByIDAndResourceOwner(ctx context.Context, shouldTri
|
||||
sq.Eq{IDPTemplateResourceOwnerCol.identifier(): authz.GetInstance(ctx).InstanceID()},
|
||||
},
|
||||
}
|
||||
stmt, scan := prepareIDPTemplateByIDQuery()
|
||||
stmt, scan := prepareIDPTemplateByIDQuery(ctx, q.client)
|
||||
query, args, err := stmt.Where(where).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-SFAew", "Errors.Query.SQLStatement")
|
||||
@ -424,7 +425,7 @@ func (q *Queries) IDPTemplates(ctx context.Context, queries *IDPTemplateSearchQu
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareIDPTemplatesQuery()
|
||||
query, scan := prepareIDPTemplatesQuery(ctx, q.client)
|
||||
eq := sq.Eq{
|
||||
IDPTemplateInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}
|
||||
@ -485,7 +486,7 @@ func (q *IDPTemplateSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuil
|
||||
return query
|
||||
}
|
||||
|
||||
func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTemplate, error)) {
|
||||
func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Row) (*IDPTemplate, error)) {
|
||||
return sq.Select(
|
||||
IDPTemplateIDCol.identifier(),
|
||||
IDPTemplateResourceOwnerCol.identifier(),
|
||||
@ -553,7 +554,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
LeftJoin(join(OIDCIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(JWTIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(GoogleIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*IDPTemplate, error) {
|
||||
idpTemplate := new(IDPTemplate)
|
||||
@ -750,7 +751,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
}
|
||||
}
|
||||
|
||||
func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplates, error)) {
|
||||
func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplates, error)) {
|
||||
return sq.Select(
|
||||
IDPTemplateIDCol.identifier(),
|
||||
IDPTemplateResourceOwnerCol.identifier(),
|
||||
@ -819,7 +820,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
LeftJoin(join(OIDCIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(JWTIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(GoogleIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*IDPTemplates, error) {
|
||||
templates := make([]*IDPTemplate, 0)
|
||||
|
@ -81,7 +81,8 @@ var (
|
||||
` LEFT JOIN projections.idp_templates2_oidc ON projections.idp_templates2.id = projections.idp_templates2_oidc.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oidc.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates2_jwt ON projections.idp_templates2.id = projections.idp_templates2_jwt.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_jwt.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates2_google ON projections.idp_templates2.id = projections.idp_templates2_google.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates2_ldap ON projections.idp_templates2.id = projections.idp_templates2_ldap.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_ldap.instance_id`
|
||||
` LEFT JOIN projections.idp_templates2_ldap ON projections.idp_templates2.id = projections.idp_templates2_ldap.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_ldap.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
idpTemplateCols = []string{
|
||||
"id",
|
||||
"resource_owner",
|
||||
@ -212,7 +213,8 @@ var (
|
||||
` LEFT JOIN projections.idp_templates2_oidc ON projections.idp_templates2.id = projections.idp_templates2_oidc.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_oidc.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates2_jwt ON projections.idp_templates2.id = projections.idp_templates2_jwt.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_jwt.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates2_google ON projections.idp_templates2.id = projections.idp_templates2_google.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates2_ldap ON projections.idp_templates2.id = projections.idp_templates2_ldap.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_ldap.instance_id`
|
||||
` LEFT JOIN projections.idp_templates2_ldap ON projections.idp_templates2.id = projections.idp_templates2_ldap.idp_id AND projections.idp_templates2.instance_id = projections.idp_templates2_ldap.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
idpTemplatesCols = []string{
|
||||
"id",
|
||||
"resource_owner",
|
||||
@ -1628,7 +1630,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -733,7 +733,7 @@ func Test_IDPPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -92,7 +93,7 @@ func (q *Queries) IDPUserLinks(ctx context.Context, queries *IDPUserLinksSearchQ
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareIDPUserLinksQuery()
|
||||
query, scan := prepareIDPUserLinksQuery(ctx, q.client)
|
||||
eq := sq.Eq{IDPUserLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||
if !withOwnerRemoved {
|
||||
eq[IDPUserLinkOwnerRemovedCol.identifier()] = false
|
||||
@ -126,7 +127,7 @@ func NewIDPUserLinksResourceOwnerSearchQuery(value string) (SearchQuery, error)
|
||||
return NewTextQuery(IDPUserLinkResourceOwnerCol, value, TextEquals)
|
||||
}
|
||||
|
||||
func prepareIDPUserLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPUserLinks, error)) {
|
||||
func prepareIDPUserLinksQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPUserLinks, error)) {
|
||||
return sq.Select(
|
||||
IDPUserLinkIDPIDCol.identifier(),
|
||||
IDPUserLinkUserIDCol.identifier(),
|
||||
@ -137,7 +138,8 @@ func prepareIDPUserLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPUserLink
|
||||
IDPUserLinkResourceOwnerCol.identifier(),
|
||||
countColumn.identifier()).
|
||||
From(idpUserLinkTable.identifier()).
|
||||
LeftJoin(join(IDPIDCol, IDPUserLinkIDPIDCol)).PlaceholderFormat(sq.Dollar),
|
||||
LeftJoin(join(IDPIDCol, IDPUserLinkIDPIDCol) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*IDPUserLinks, error) {
|
||||
idps := make([]*IDPUserLink, 0)
|
||||
var count uint64
|
||||
|
@ -21,7 +21,8 @@ var (
|
||||
` projections.idp_user_links3.resource_owner,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.idp_user_links3` +
|
||||
` LEFT JOIN projections.idps3 ON projections.idp_user_links3.idp_id = projections.idps3.id`)
|
||||
` LEFT JOIN projections.idps3 ON projections.idp_user_links3.idp_id = projections.idps3.id AND projections.idp_user_links3.instance_id = projections.idps3.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`)
|
||||
idpUserLinksCols = []string{
|
||||
"idp_id",
|
||||
"user_id",
|
||||
@ -139,7 +140,7 @@ func Test_IDPUserLinkPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -159,7 +160,7 @@ func (q *Queries) SearchInstances(ctx context.Context, queries *InstanceSearchQu
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
filter, query, scan := prepareInstancesQuery()
|
||||
filter, query, scan := prepareInstancesQuery(ctx, q.client)
|
||||
stmt, args, err := query(queries.toQuery(filter)).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInvalidArgument(err, "QUERY-M9fow", "Errors.Query.SQLStatement")
|
||||
@ -184,7 +185,7 @@ func (q *Queries) Instance(ctx context.Context, shouldTriggerBulk bool) (_ *Inst
|
||||
projection.InstanceProjection.Trigger(ctx)
|
||||
}
|
||||
|
||||
stmt, scan := prepareInstanceDomainQuery(authz.GetInstance(ctx).RequestedDomain())
|
||||
stmt, scan := prepareInstanceDomainQuery(ctx, q.client, authz.GetInstance(ctx).RequestedDomain())
|
||||
query, args, err := stmt.Where(sq.Eq{
|
||||
InstanceColumnID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}).ToSql()
|
||||
@ -203,7 +204,7 @@ func (q *Queries) InstanceByHost(ctx context.Context, host string) (_ authz.Inst
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := prepareAuthzInstanceQuery(host)
|
||||
stmt, scan := prepareAuthzInstanceQuery(ctx, q.client, host)
|
||||
host = strings.Split(host, ":")[0] //remove possible port
|
||||
query, args, err := stmt.Where(sq.Eq{
|
||||
InstanceDomainDomainCol.identifier(): host,
|
||||
@ -231,7 +232,7 @@ func (q *Queries) GetDefaultLanguage(ctx context.Context) language.Tag {
|
||||
return instance.DefaultLanguage()
|
||||
}
|
||||
|
||||
func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Instance, error)) {
|
||||
func prepareInstanceQuery(ctx context.Context, db prepareDatabase, host string) (sq.SelectBuilder, func(*sql.Row) (*Instance, error)) {
|
||||
return sq.Select(
|
||||
InstanceColumnID.identifier(),
|
||||
InstanceColumnCreationDate.identifier(),
|
||||
@ -243,7 +244,8 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
|
||||
InstanceColumnConsoleAppID.identifier(),
|
||||
InstanceColumnDefaultLanguage.identifier(),
|
||||
).
|
||||
From(instanceTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
From(instanceTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*Instance, error) {
|
||||
instance := &Instance{host: host}
|
||||
lang := ""
|
||||
@ -269,7 +271,7 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
|
||||
}
|
||||
}
|
||||
|
||||
func prepareInstancesQuery() (sq.SelectBuilder, func(sq.SelectBuilder) sq.SelectBuilder, func(*sql.Rows) (*Instances, error)) {
|
||||
func prepareInstancesQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(sq.SelectBuilder) sq.SelectBuilder, func(*sql.Rows) (*Instances, error)) {
|
||||
instanceFilterTable := instanceTable.setAlias(InstancesFilterTableAlias)
|
||||
instanceFilterIDColumn := InstanceColumnID.setTable(instanceFilterTable)
|
||||
instanceFilterCountColumn := InstancesFilterTableAlias + ".count"
|
||||
@ -298,7 +300,7 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(sq.SelectBuilder) sq.Select
|
||||
InstanceDomainSequenceCol.identifier(),
|
||||
).FromSelect(builder, InstancesFilterTableAlias).
|
||||
LeftJoin(join(InstanceColumnID, instanceFilterIDColumn)).
|
||||
LeftJoin(join(InstanceDomainInstanceIDCol, instanceFilterIDColumn)).
|
||||
LeftJoin(join(InstanceDomainInstanceIDCol, instanceFilterIDColumn) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar)
|
||||
},
|
||||
func(rows *sql.Rows) (*Instances, error) {
|
||||
@ -373,7 +375,7 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(sq.SelectBuilder) sq.Select
|
||||
}
|
||||
}
|
||||
|
||||
func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows) (*Instance, error)) {
|
||||
func prepareInstanceDomainQuery(ctx context.Context, db prepareDatabase, host string) (sq.SelectBuilder, func(*sql.Rows) (*Instance, error)) {
|
||||
return sq.Select(
|
||||
InstanceColumnID.identifier(),
|
||||
InstanceColumnCreationDate.identifier(),
|
||||
@ -393,7 +395,7 @@ func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows)
|
||||
InstanceDomainSequenceCol.identifier(),
|
||||
).
|
||||
From(instanceTable.identifier()).
|
||||
LeftJoin(join(InstanceDomainInstanceIDCol, InstanceColumnID)).
|
||||
LeftJoin(join(InstanceDomainInstanceIDCol, InstanceColumnID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*Instance, error) {
|
||||
instance := &Instance{
|
||||
@ -455,7 +457,7 @@ func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAuthzInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Rows) (*Instance, error)) {
|
||||
func prepareAuthzInstanceQuery(ctx context.Context, db prepareDatabase, host string) (sq.SelectBuilder, func(*sql.Rows) (*Instance, error)) {
|
||||
return sq.Select(
|
||||
InstanceColumnID.identifier(),
|
||||
InstanceColumnCreationDate.identifier(),
|
||||
@ -478,7 +480,7 @@ func prepareAuthzInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Rows) (
|
||||
).
|
||||
From(instanceTable.identifier()).
|
||||
LeftJoin(join(InstanceDomainInstanceIDCol, InstanceColumnID)).
|
||||
LeftJoin(join(SecurityPolicyColumnInstanceID, InstanceColumnID)).
|
||||
LeftJoin(join(SecurityPolicyColumnInstanceID, InstanceColumnID) + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*Instance, error) {
|
||||
instance := &Instance{
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/call"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
@ -61,7 +62,7 @@ func (q *Queries) SearchInstanceDomains(ctx context.Context, queries *InstanceDo
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareInstanceDomainsQuery()
|
||||
query, scan := prepareInstanceDomainsQuery(ctx, q.client)
|
||||
stmt, args, err := queries.toQuery(query).
|
||||
Where(sq.Eq{
|
||||
InstanceDomainInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
@ -77,7 +78,7 @@ func (q *Queries) SearchInstanceDomainsGlobal(ctx context.Context, queries *Inst
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareInstanceDomainsQuery()
|
||||
query, scan := prepareInstanceDomainsQuery(ctx, q.client)
|
||||
stmt, args, err := queries.toQuery(query).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInvalidArgument(err, "QUERY-IHhLR", "Errors.Query.SQLStatement")
|
||||
@ -99,7 +100,7 @@ func (q *Queries) queryInstanceDomains(ctx context.Context, stmt string, scan fu
|
||||
return domains, err
|
||||
}
|
||||
|
||||
func prepareInstanceDomainsQuery() (sq.SelectBuilder, func(*sql.Rows) (*InstanceDomains, error)) {
|
||||
func prepareInstanceDomainsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*InstanceDomains, error)) {
|
||||
return sq.Select(
|
||||
InstanceDomainCreationDateCol.identifier(),
|
||||
InstanceDomainChangeDateCol.identifier(),
|
||||
@ -109,7 +110,8 @@ func prepareInstanceDomainsQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instance
|
||||
InstanceDomainIsGeneratedCol.identifier(),
|
||||
InstanceDomainIsPrimaryCol.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(instanceDomainsTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
).From(instanceDomainsTable.identifier() + db.Timetravel(call.Took(ctx))).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*InstanceDomains, error) {
|
||||
domains := make([]*InstanceDomain, 0)
|
||||
var count uint64
|
||||
|
@ -9,6 +9,29 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
prepareInstanceDomainsStmt = `SELECT projections.instance_domains.creation_date,` +
|
||||
` projections.instance_domains.change_date,` +
|
||||
` projections.instance_domains.sequence,` +
|
||||
` projections.instance_domains.domain,` +
|
||||
` projections.instance_domains.instance_id,` +
|
||||
` projections.instance_domains.is_generated,` +
|
||||
` projections.instance_domains.is_primary,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.instance_domains` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
prepareInstanceDomainsCols = []string{
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"domain",
|
||||
"instance_id",
|
||||
"is_generated",
|
||||
"is_primary",
|
||||
"count",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_InstanceDomainPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
@ -25,15 +48,7 @@ func Test_InstanceDomainPrepares(t *testing.T) {
|
||||
prepare: prepareInstanceDomainsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.instance_domains.creation_date,`+
|
||||
` projections.instance_domains.change_date,`+
|
||||
` projections.instance_domains.sequence,`+
|
||||
` projections.instance_domains.domain,`+
|
||||
` projections.instance_domains.instance_id,`+
|
||||
` projections.instance_domains.is_generated,`+
|
||||
` projections.instance_domains.is_primary,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.instance_domains`),
|
||||
regexp.QuoteMeta(prepareInstanceDomainsStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -45,25 +60,8 @@ func Test_InstanceDomainPrepares(t *testing.T) {
|
||||
prepare: prepareInstanceDomainsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.instance_domains.creation_date,`+
|
||||
` projections.instance_domains.change_date,`+
|
||||
` projections.instance_domains.sequence,`+
|
||||
` projections.instance_domains.domain,`+
|
||||
` projections.instance_domains.instance_id,`+
|
||||
` projections.instance_domains.is_generated,`+
|
||||
` projections.instance_domains.is_primary,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.instance_domains`),
|
||||
[]string{
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"domain",
|
||||
"instance_id",
|
||||
"is_generated",
|
||||
"is_primary",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareInstanceDomainsStmt),
|
||||
prepareInstanceDomainsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
testNow,
|
||||
@ -99,25 +97,8 @@ func Test_InstanceDomainPrepares(t *testing.T) {
|
||||
prepare: prepareInstanceDomainsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.instance_domains.creation_date,`+
|
||||
` projections.instance_domains.change_date,`+
|
||||
` projections.instance_domains.sequence,`+
|
||||
` projections.instance_domains.domain,`+
|
||||
` projections.instance_domains.instance_id,`+
|
||||
` projections.instance_domains.is_generated,`+
|
||||
` projections.instance_domains.is_primary,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.instance_domains`),
|
||||
[]string{
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"domain",
|
||||
"instance_id",
|
||||
"is_generated",
|
||||
"is_primary",
|
||||
"count",
|
||||
},
|
||||
regexp.QuoteMeta(prepareInstanceDomainsStmt),
|
||||
prepareInstanceDomainsCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
testNow,
|
||||
@ -171,15 +152,7 @@ func Test_InstanceDomainPrepares(t *testing.T) {
|
||||
prepare: prepareInstanceDomainsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.instance_domains.creation_date,`+
|
||||
` projections.instance_domains.change_date,`+
|
||||
` projections.instance_domains.sequence,`+
|
||||
` projections.instance_domains.domain,`+
|
||||
` projections.instance_domains.instance_id,`+
|
||||
` projections.instance_domains.is_generated,`+
|
||||
` projections.instance_domains.is_primary,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.instance_domains`),
|
||||
regexp.QuoteMeta(prepareInstanceDomainsStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -194,7 +167,7 @@ func Test_InstanceDomainPrepares(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user