mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 16:37:24 +00:00
feat(database): support for postgres (#3998)
* beginning with postgres statements * try pgx * use pgx * database * init works for postgres * arrays working * init for cockroach * init * start tests * tests * TESTS * ch * ch * chore: use go 1.18 * read stmts * fix typo * tests * connection string * add missing error handler * cleanup * start all apis * go mod tidy * old update * switch back to minute * on conflict * replace string slice with `database.StringArray` in db models * fix tests and start * update go version in dockerfile * setup go * clean up * remove notification migration * update * docs: add deploy guide for postgres * fix: revert sonyflake * use `database.StringArray` for daos * use `database.StringArray` every where * new tables * index naming, metadata primary key, project grant role key type * docs(postgres): change to beta * chore: correct compose * fix(defaults): add empty postgres config * refactor: remove unused code * docs: add postgres to self hosted * fix broken link * so? * change title * add mdx to link * fix stmt * update goreleaser in test-code * docs: improve postgres example * update more projections * fix: add beta log for postgres * revert index name change * prerelease * fix: add sequence to v1 "reduce paniced" * log if nil * add logging * fix: log output * fix(import): check if org exists and user * refactor: imports * fix(user): ignore malformed events * refactor: method naming * fix: test * refactor: correct errors.Is call * ci: don't build dev binaries on main * fix(go releaser): update version to 1.11.0 * fix(user): projection should not break * fix(user): handle error properly * docs: correct config example * Update .releaserc.js * Update .releaserc.js Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: Elio Bischof <eliobischof@gmail.com>
This commit is contained in:
parent
d6c9815945
commit
77b4fc5487
6
.github/workflows/test-code.yml
vendored
6
.github/workflows/test-code.yml
vendored
@ -13,6 +13,10 @@ jobs:
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.19
|
||||
- name: Source checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up QEMU
|
||||
@ -26,7 +30,7 @@ jobs:
|
||||
uses: goreleaser/goreleaser-action@v3
|
||||
with:
|
||||
install-only: true
|
||||
version: v1.8.3
|
||||
version: v1.10.3
|
||||
- name: Build and Unit Test
|
||||
run: GOOS="linux" GOARCH="amd64" goreleaser build --id prod --snapshot --single-target --rm-dist --output .artifacts/zitadel/zitadel
|
||||
- name: Publish go coverage
|
||||
|
4
.github/workflows/zitadel.yml
vendored
4
.github/workflows/zitadel.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version: 1.19
|
||||
- name: Source checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
@ -65,7 +65,7 @@ jobs:
|
||||
if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: v1.8.3
|
||||
version: v1.11.0
|
||||
args: release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
@ -24,8 +24,7 @@ before:
|
||||
- sh -c "cp -r .artifacts/console/* internal/api/ui/console/static/"
|
||||
|
||||
builds:
|
||||
- id: prod
|
||||
env:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
@ -36,12 +35,6 @@ builds:
|
||||
- arm64
|
||||
ldflags:
|
||||
-s -w -X github.com/zitadel/zitadel/cmd/build.version={{.Version}} -X github.com/zitadel/zitadel/cmd/build.commit={{.Commit}} -X github.com/zitadel/zitadel/cmd/build.date={{.Date}}
|
||||
- id: dev
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
binary: zitadel-debug
|
||||
gcflags: all=-N -l
|
||||
ldflags: ""
|
||||
|
||||
dist: .artifacts/goreleaser
|
||||
|
||||
@ -54,8 +47,6 @@ dockers:
|
||||
dockerfile: build/Dockerfile
|
||||
build_flag_templates:
|
||||
- "--platform=linux/amd64"
|
||||
ids:
|
||||
- prod
|
||||
- image_templates:
|
||||
- ghcr.io/zitadel/zitadel:{{ .Tag }}-arm64
|
||||
- ghcr.io/zitadel/zitadel:{{ .ShortCommit }}-arm64
|
||||
@ -64,8 +55,6 @@ dockers:
|
||||
dockerfile: build/Dockerfile
|
||||
build_flag_templates:
|
||||
- "--platform=linux/arm64"
|
||||
ids:
|
||||
- prod
|
||||
|
||||
docker_manifests:
|
||||
- id: zitadel-latest
|
||||
@ -84,8 +73,6 @@ docker_manifests:
|
||||
|
||||
archives:
|
||||
- name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
|
||||
builds:
|
||||
- prod
|
||||
replacements:
|
||||
darwin: Darwin
|
||||
linux: Linux
|
||||
|
@ -1,4 +1,4 @@
|
||||
ARG GO_VERSION=1.17
|
||||
ARG GO_VERSION=1.19
|
||||
|
||||
#######################
|
||||
## Go dependencies
|
||||
|
@ -45,6 +45,7 @@ HTTP1HostHeader: "host"
|
||||
WebAuthNName: ZITADEL
|
||||
|
||||
Database:
|
||||
# CockroachDB is the default datbase of ZITADEL
|
||||
cockroach:
|
||||
Host: localhost
|
||||
Port: 26257
|
||||
@ -69,6 +70,32 @@ Database:
|
||||
RootCert: ""
|
||||
Cert: ""
|
||||
Key: ""
|
||||
# Postgres is used as soon as a value is set
|
||||
# The values describe the possible fields to set values
|
||||
postgres:
|
||||
Host:
|
||||
Port:
|
||||
Database:
|
||||
MaxOpenConns:
|
||||
MaxConnLifetime:
|
||||
MaxConnIdleTime:
|
||||
Options:
|
||||
User:
|
||||
Username:
|
||||
Password:
|
||||
SSL:
|
||||
Mode:
|
||||
RootCert:
|
||||
Cert:
|
||||
Key:
|
||||
Admin:
|
||||
Username:
|
||||
Password:
|
||||
SSL:
|
||||
Mode:
|
||||
RootCert:
|
||||
Cert:
|
||||
Key:
|
||||
|
||||
Machine:
|
||||
# Cloud hosted VMs need to specify their metadata endpoint so that the machine can be uniquely identified.
|
||||
|
@ -2,27 +2,20 @@ package initialise
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
|
||||
"github.com/jackc/pgconn"
|
||||
)
|
||||
|
||||
func exists(query string, args ...interface{}) func(*sql.DB) (exists bool, err error) {
|
||||
return func(db *sql.DB) (exists bool, err error) {
|
||||
row := db.QueryRow("SELECT EXISTS("+query+")", args...)
|
||||
err = row.Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
}
|
||||
|
||||
func exec(stmt string, args ...interface{}) func(*sql.DB) error {
|
||||
return func(db *sql.DB) error {
|
||||
func exec(db *sql.DB, stmt string, possibleErrCodes []string, args ...interface{}) error {
|
||||
_, err := db.Exec(stmt, args...)
|
||||
pgErr := new(pgconn.PgError)
|
||||
if errors.As(err, &pgErr) {
|
||||
for _, possibleCode := range possibleErrCodes {
|
||||
if possibleCode == pgErr.Code {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func verify(db *sql.DB, checkExists func(*sql.DB) (bool, error), create func(*sql.DB) error) error {
|
||||
exists, err := checkExists(db)
|
||||
if exists || err != nil {
|
||||
return err
|
||||
}
|
||||
return create(db)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package initialise
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"embed"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@ -12,6 +12,26 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed sql/cockroach/*
|
||||
//go:embed sql/postgres/*
|
||||
stmts embed.FS
|
||||
|
||||
createUserStmt string
|
||||
grantStmt string
|
||||
databaseStmt string
|
||||
createEventstoreStmt string
|
||||
createProjectionsStmt string
|
||||
createSystemStmt string
|
||||
createEncryptionKeysStmt string
|
||||
createEventsStmt string
|
||||
createSystemSequenceStmt string
|
||||
createUniqueConstraints string
|
||||
|
||||
roleAlreadyExistsCode = "42710"
|
||||
dbAlreadyExistsCode = "42P04"
|
||||
)
|
||||
|
||||
func New() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
@ -39,6 +59,7 @@ The user provided by flags needs privileges to
|
||||
|
||||
func InitAll(config *Config) {
|
||||
id.Configure(config.Machine)
|
||||
|
||||
err := initialise(config.Database,
|
||||
VerifyUser(config.Database.Username(), config.Database.Password()),
|
||||
VerifyDatabase(config.Database.Database()),
|
||||
@ -53,22 +74,85 @@ func InitAll(config *Config) {
|
||||
func initialise(config database.Config, steps ...func(*sql.DB) error) error {
|
||||
logging.Info("initialization started")
|
||||
|
||||
err := ReadStmts(config.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db, err := database.Connect(config, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = Initialise(db, steps...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.Close()
|
||||
defer db.Close()
|
||||
|
||||
return Init(db, steps...)
|
||||
}
|
||||
|
||||
func Initialise(db *sql.DB, steps ...func(*sql.DB) error) error {
|
||||
func Init(db *sql.DB, steps ...func(*sql.DB) error) error {
|
||||
for _, step := range steps {
|
||||
if err := step(db); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadStmts(typ string) (err error) {
|
||||
createUserStmt, err = readStmt(typ, "01_user")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
databaseStmt, err = readStmt(typ, "02_database")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
grantStmt, err = readStmt(typ, "03_grant_user")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createEventstoreStmt, err = readStmt(typ, "04_eventstore")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createProjectionsStmt, err = readStmt(typ, "05_projections")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createSystemStmt, err = readStmt(typ, "06_system")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createEncryptionKeysStmt, err = readStmt(typ, "07_encryption_keys_table")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createEventsStmt, err = readStmt(typ, "08_events_table")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createSystemSequenceStmt, err = readStmt(typ, "09_system_sequence")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
createUniqueConstraints, err = readStmt(typ, "10_unique_constraints_table")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readStmt(typ, step string) (string, error) {
|
||||
stmt, err := stmts.ReadFile("sql/" + typ + "/" + step + ".sql")
|
||||
return string(stmt), err
|
||||
}
|
||||
|
@ -31,18 +31,6 @@ func prepareDB(t *testing.T, expectations ...expectation) db {
|
||||
|
||||
type expectation func(m sqlmock.Sqlmock)
|
||||
|
||||
func expectExists(query string, value bool, args ...driver.Value) expectation {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectQuery(regexp.QuoteMeta(query)).WithArgs(args...).WillReturnRows(sqlmock.NewRows([]string{"exists"}).AddRow(value))
|
||||
}
|
||||
}
|
||||
|
||||
func expectQueryErr(query string, err error, args ...driver.Value) expectation {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectQuery(regexp.QuoteMeta(query)).WithArgs(args...).WillReturnError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func expectExec(stmt string, err error, args ...driver.Value) expectation {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
query := m.ExpectExec(regexp.QuoteMeta(stmt)).WithArgs(args...)
|
||||
|
@ -1 +0,0 @@
|
||||
CREATE SCHEMA eventstore
|
@ -1 +0,0 @@
|
||||
CREATE SCHEMA projections
|
@ -1 +0,0 @@
|
||||
CREATE SCHEMA system;
|
@ -1 +0,0 @@
|
||||
SET experimental_enable_hash_sharded_indexes = on
|
@ -1 +0,0 @@
|
||||
CREATE SEQUENCE eventstore.system_seq
|
@ -1,2 +1,2 @@
|
||||
-- replace %[1]s with the name of the user
|
||||
CREATE USER %[1]s WITH PASSWORD $1
|
||||
CREATE USER IF NOT EXISTS %[1]s
|
@ -1,2 +1,2 @@
|
||||
-- replace %[1]s with the name of the database
|
||||
CREATE DATABASE %[1]s
|
||||
CREATE DATABASE IF NOT EXISTS %[1]s
|
3
cmd/initialise/sql/cockroach/04_eventstore.sql
Normal file
3
cmd/initialise/sql/cockroach/04_eventstore.sql
Normal file
@ -0,0 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS eventstore;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA eventstore TO %[1]s;
|
3
cmd/initialise/sql/cockroach/05_projections.sql
Normal file
3
cmd/initialise/sql/cockroach/05_projections.sql
Normal file
@ -0,0 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS projections;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA projections TO %[1]s;
|
3
cmd/initialise/sql/cockroach/06_system.sql
Normal file
3
cmd/initialise/sql/cockroach/06_system.sql
Normal file
@ -0,0 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS system;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA system TO %[1]s;
|
@ -1,4 +1,4 @@
|
||||
CREATE TABLE system.encryption_keys (
|
||||
CREATE TABLE IF NOT EXISTS system.encryption_keys (
|
||||
id TEXT NOT NULL
|
||||
, key TEXT NOT NULL
|
||||
|
@ -1,4 +1,6 @@
|
||||
CREATE TABLE eventstore.events (
|
||||
SET experimental_enable_hash_sharded_indexes = on;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS eventstore.events (
|
||||
id UUID DEFAULT gen_random_uuid()
|
||||
, event_type TEXT NOT NULL
|
||||
, aggregate_type TEXT NOT NULL
|
||||
@ -22,4 +24,4 @@ CREATE TABLE eventstore.events (
|
||||
, INDEX max_sequence (aggregate_type, aggregate_id, event_sequence DESC, instance_id)
|
||||
, CONSTRAINT previous_sequence_unique UNIQUE (previous_aggregate_sequence DESC, instance_id)
|
||||
, CONSTRAINT prev_agg_type_seq_unique UNIQUE(previous_aggregate_type_sequence, instance_id)
|
||||
)
|
||||
);
|
1
cmd/initialise/sql/cockroach/09_system_sequence.sql
Normal file
1
cmd/initialise/sql/cockroach/09_system_sequence.sql
Normal file
@ -0,0 +1 @@
|
||||
CREATE SEQUENCE IF NOT EXISTS eventstore.system_seq
|
@ -1,4 +1,4 @@
|
||||
CREATE TABLE eventstore.unique_constraints (
|
||||
CREATE TABLE IF NOT EXISTS eventstore.unique_constraints (
|
||||
instance_id TEXT,
|
||||
unique_type TEXT,
|
||||
unique_field TEXT,
|
1
cmd/initialise/sql/postgres/01_user.sql
Normal file
1
cmd/initialise/sql/postgres/01_user.sql
Normal file
@ -0,0 +1 @@
|
||||
CREATE USER %[1]s
|
1
cmd/initialise/sql/postgres/02_database.sql
Normal file
1
cmd/initialise/sql/postgres/02_database.sql
Normal file
@ -0,0 +1 @@
|
||||
CREATE DATABASE %[1]s
|
3
cmd/initialise/sql/postgres/03_grant_user.sql
Normal file
3
cmd/initialise/sql/postgres/03_grant_user.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- replace the first %[1]s with the database
|
||||
-- replace the second \%[2]s with the user
|
||||
GRANT ALL ON DATABASE %[1]s TO %[2]s;
|
3
cmd/initialise/sql/postgres/04_eventstore.sql
Normal file
3
cmd/initialise/sql/postgres/04_eventstore.sql
Normal file
@ -0,0 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS eventstore;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA eventstore TO %[1]s;
|
3
cmd/initialise/sql/postgres/05_projections.sql
Normal file
3
cmd/initialise/sql/postgres/05_projections.sql
Normal file
@ -0,0 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS projections;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA projections TO %[1]s;
|
3
cmd/initialise/sql/postgres/06_system.sql
Normal file
3
cmd/initialise/sql/postgres/06_system.sql
Normal file
@ -0,0 +1,3 @@
|
||||
CREATE SCHEMA IF NOT EXISTS system;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA system TO %[1]s;
|
6
cmd/initialise/sql/postgres/07_encryption_keys_table.sql
Normal file
6
cmd/initialise/sql/postgres/07_encryption_keys_table.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS system.encryption_keys (
|
||||
id TEXT NOT NULL
|
||||
, key TEXT NOT NULL
|
||||
|
||||
, PRIMARY KEY (id)
|
||||
);
|
25
cmd/initialise/sql/postgres/08_events_table.sql
Normal file
25
cmd/initialise/sql/postgres/08_events_table.sql
Normal file
@ -0,0 +1,25 @@
|
||||
CREATE TABLE IF NOT EXISTS eventstore.events (
|
||||
id UUID DEFAULT gen_random_uuid()
|
||||
, event_type TEXT NOT NULL
|
||||
, aggregate_type TEXT NOT NULL
|
||||
, aggregate_id TEXT NOT NULL
|
||||
, aggregate_version TEXT NOT NULL
|
||||
, event_sequence BIGINT NOT NULL
|
||||
, previous_aggregate_sequence BIGINT
|
||||
, previous_aggregate_type_sequence INT8
|
||||
, creation_date TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
, event_data JSONB
|
||||
, editor_user TEXT NOT NULL
|
||||
, editor_service TEXT NOT NULL
|
||||
, resource_owner TEXT NOT NULL
|
||||
, instance_id TEXT NOT NULL
|
||||
|
||||
, PRIMARY KEY (event_sequence, instance_id)
|
||||
, CONSTRAINT previous_sequence_unique UNIQUE(previous_aggregate_sequence, instance_id)
|
||||
, CONSTRAINT prev_agg_type_seq_unique UNIQUE(previous_aggregate_type_sequence, instance_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS agg_type_agg_id ON eventstore.events (aggregate_type, aggregate_id, instance_id);
|
||||
CREATE INDEX IF NOT EXISTS agg_type ON eventstore.events (aggregate_type, instance_id);
|
||||
CREATE INDEX IF NOT EXISTS agg_type_seq ON eventstore.events (aggregate_type, event_sequence DESC, instance_id);
|
||||
CREATE INDEX IF NOT EXISTS max_sequence ON eventstore.events (aggregate_type, aggregate_id, event_sequence DESC, instance_id);
|
1
cmd/initialise/sql/postgres/09_system_sequence.sql
Normal file
1
cmd/initialise/sql/postgres/09_system_sequence.sql
Normal file
@ -0,0 +1 @@
|
||||
CREATE SEQUENCE IF NOT EXISTS eventstore.system_seq;
|
@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS eventstore.unique_constraints (
|
||||
instance_id TEXT,
|
||||
unique_type TEXT,
|
||||
unique_field TEXT,
|
||||
PRIMARY KEY (instance_id, unique_type, unique_field)
|
||||
);
|
@ -10,13 +10,6 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
)
|
||||
|
||||
var (
|
||||
searchDatabase = "SELECT database_name FROM [show databases] WHERE database_name = $1"
|
||||
|
||||
//go:embed sql/02_database.sql
|
||||
databaseStmt string
|
||||
)
|
||||
|
||||
func newDatabase() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "database",
|
||||
@ -40,11 +33,10 @@ The user provided by flags needs priviledge to
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyDatabase(database string) func(*sql.DB) error {
|
||||
func VerifyDatabase(databaseName string) func(*sql.DB) error {
|
||||
return func(db *sql.DB) error {
|
||||
return verify(db,
|
||||
exists(searchDatabase, database),
|
||||
exec(fmt.Sprintf(databaseStmt, database)),
|
||||
)
|
||||
logging.WithFields("database", databaseName).Info("verify database")
|
||||
|
||||
return exec(db, fmt.Sprintf(string(databaseStmt), databaseName), []string{dbAlreadyExistsCode})
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,12 @@ import (
|
||||
)
|
||||
|
||||
func Test_verifyDB(t *testing.T) {
|
||||
err := ReadStmts("cockroach") //TODO: check all dialects
|
||||
if err != nil {
|
||||
t.Errorf("unable to read stmts: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
type args struct {
|
||||
db db
|
||||
database string
|
||||
@ -16,20 +22,11 @@ func Test_verifyDB(t *testing.T) {
|
||||
args args
|
||||
targetErr error
|
||||
}{
|
||||
{
|
||||
name: "exists fails",
|
||||
args: args{
|
||||
db: prepareDB(t, expectQueryErr("SELECT EXISTS(SELECT database_name FROM [show databases] WHERE database_name = $1)", sql.ErrConnDone, "zitadel")),
|
||||
database: "zitadel",
|
||||
},
|
||||
targetErr: sql.ErrConnDone,
|
||||
},
|
||||
{
|
||||
name: "doesn't exists, create fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT database_name FROM [show databases] WHERE database_name = $1)", false, "zitadel"),
|
||||
expectExec("CREATE DATABASE zitadel", sql.ErrTxDone),
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS zitadel", sql.ErrTxDone),
|
||||
),
|
||||
database: "zitadel",
|
||||
},
|
||||
@ -39,8 +36,7 @@ func Test_verifyDB(t *testing.T) {
|
||||
name: "doesn't exists, create successful",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT database_name FROM [show databases] WHERE database_name = $1)", false, "zitadel"),
|
||||
expectExec("CREATE DATABASE zitadel", nil),
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS zitadel", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
},
|
||||
@ -50,7 +46,7 @@ func Test_verifyDB(t *testing.T) {
|
||||
name: "already exists",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT database_name FROM [show databases] WHERE database_name = $1)", true, "zitadel"),
|
||||
expectExec("-- replace zitadel with the name of the database\nCREATE DATABASE IF NOT EXISTS zitadel", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
},
|
||||
|
@ -10,12 +10,6 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
)
|
||||
|
||||
var (
|
||||
searchGrant = "SELECT * FROM [SHOW GRANTS ON DATABASE %s] where grantee = $1 AND privilege_type = 'ALL'"
|
||||
//go:embed sql/03_grant_user.sql
|
||||
grantStmt string
|
||||
)
|
||||
|
||||
func newGrant() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "grant",
|
||||
@ -34,12 +28,10 @@ Prereqesits:
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyGrant(database, username string) func(*sql.DB) error {
|
||||
func VerifyGrant(databaseName, username string) func(*sql.DB) error {
|
||||
return func(db *sql.DB) error {
|
||||
logging.WithFields("user", username, "database", database).Info("verify grant")
|
||||
return verify(db,
|
||||
exists(fmt.Sprintf(searchGrant, database), username),
|
||||
exec(fmt.Sprintf(grantStmt, database, username)),
|
||||
)
|
||||
logging.WithFields("user", username, "database", databaseName).Info("verify grant")
|
||||
|
||||
return exec(db, fmt.Sprintf(grantStmt, databaseName, username), nil)
|
||||
}
|
||||
}
|
||||
|
@ -17,20 +17,10 @@ func Test_verifyGrant(t *testing.T) {
|
||||
args args
|
||||
targetErr error
|
||||
}{
|
||||
{
|
||||
name: "exists fails",
|
||||
args: args{
|
||||
db: prepareDB(t, expectQueryErr("SELECT EXISTS(SELECT * FROM [SHOW GRANTS ON DATABASE zitadel] where grantee = $1 AND privilege_type = 'ALL'", sql.ErrConnDone, "zitadel-user")),
|
||||
database: "zitadel",
|
||||
username: "zitadel-user",
|
||||
},
|
||||
targetErr: sql.ErrConnDone,
|
||||
},
|
||||
{
|
||||
name: "doesn't exists, create fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT * FROM [SHOW GRANTS ON DATABASE zitadel] where grantee = $1 AND privilege_type = 'ALL'", false, "zitadel-user"),
|
||||
expectExec("GRANT ALL ON DATABASE zitadel TO zitadel-user", sql.ErrTxDone),
|
||||
),
|
||||
database: "zitadel",
|
||||
@ -42,7 +32,6 @@ func Test_verifyGrant(t *testing.T) {
|
||||
name: "correct",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT * FROM [SHOW GRANTS ON DATABASE zitadel] where grantee = $1 AND privilege_type = 'ALL'", false, "zitadel-user"),
|
||||
expectExec("GRANT ALL ON DATABASE zitadel TO zitadel-user", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
@ -54,7 +43,7 @@ func Test_verifyGrant(t *testing.T) {
|
||||
name: "already exists",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT * FROM [SHOW GRANTS ON DATABASE zitadel] where grantee = $1 AND privilege_type = 'ALL'", true, "zitadel-user"),
|
||||
expectExec("GRANT ALL ON DATABASE zitadel TO zitadel-user", nil),
|
||||
),
|
||||
database: "zitadel",
|
||||
username: "zitadel-user",
|
||||
|
@ -10,12 +10,6 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
)
|
||||
|
||||
var (
|
||||
searchUser = "SELECT username FROM [show roles] WHERE username = $1"
|
||||
//go:embed sql/01_user.sql
|
||||
createUserStmt string
|
||||
)
|
||||
|
||||
func newUser() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "user",
|
||||
@ -42,9 +36,11 @@ The user provided by flags needs priviledge to
|
||||
func VerifyUser(username, password string) func(*sql.DB) error {
|
||||
return func(db *sql.DB) error {
|
||||
logging.WithFields("username", username).Info("verify user")
|
||||
return verify(db,
|
||||
exists(searchUser, username),
|
||||
exec(fmt.Sprintf(createUserStmt, username), &sql.NullString{String: password, Valid: password != ""}),
|
||||
)
|
||||
|
||||
if password != "" {
|
||||
createUserStmt += " WITH PASSWORD '" + password + "'"
|
||||
}
|
||||
|
||||
return exec(db, fmt.Sprintf(createUserStmt, username), []string{roleAlreadyExistsCode})
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,12 @@ import (
|
||||
)
|
||||
|
||||
func Test_verifyUser(t *testing.T) {
|
||||
err := ReadStmts("cockroach") //TODO: check all dialects
|
||||
if err != nil {
|
||||
t.Errorf("unable to read stmts: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
type args struct {
|
||||
db db
|
||||
username string
|
||||
@ -17,21 +23,11 @@ func Test_verifyUser(t *testing.T) {
|
||||
args args
|
||||
targetErr error
|
||||
}{
|
||||
{
|
||||
name: "exists fails",
|
||||
args: args{
|
||||
db: prepareDB(t, expectQueryErr("SELECT EXISTS(SELECT username FROM [show roles] WHERE username = $1)", sql.ErrConnDone, "zitadel-user")),
|
||||
username: "zitadel-user",
|
||||
password: "",
|
||||
},
|
||||
targetErr: sql.ErrConnDone,
|
||||
},
|
||||
{
|
||||
name: "doesn't exists, create fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT username FROM [show roles] WHERE username = $1)", false, "zitadel-user"),
|
||||
expectExec("CREATE USER zitadel-user WITH PASSWORD $1", sql.ErrTxDone, nil),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user", sql.ErrTxDone),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "",
|
||||
@ -42,8 +38,7 @@ func Test_verifyUser(t *testing.T) {
|
||||
name: "correct without password",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT username FROM [show roles] WHERE username = $1)", false, "zitadel-user"),
|
||||
expectExec("CREATE USER zitadel-user WITH PASSWORD $1", nil, nil),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user", nil),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "",
|
||||
@ -54,8 +49,7 @@ func Test_verifyUser(t *testing.T) {
|
||||
name: "correct with password",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT username FROM [show roles] WHERE username = $1)", false, "zitadel-user"),
|
||||
expectExec("CREATE USER zitadel-user WITH PASSWORD $1", nil, "password"),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user WITH PASSWORD 'password'", nil),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "password",
|
||||
@ -66,7 +60,7 @@ func Test_verifyUser(t *testing.T) {
|
||||
name: "already exists",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectExists("SELECT EXISTS(SELECT username FROM [show roles] WHERE username = $1)", true, "zitadel-user"),
|
||||
expectExec("-- replace zitadel-user with the name of the user\nCREATE USER IF NOT EXISTS zitadel-user WITH PASSWORD 'password'", nil),
|
||||
),
|
||||
username: "zitadel-user",
|
||||
password: "",
|
||||
|
@ -3,11 +3,12 @@ package initialise
|
||||
import (
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
)
|
||||
|
||||
@ -20,29 +21,6 @@ const (
|
||||
encryptionKeysTable = "encryption_keys"
|
||||
)
|
||||
|
||||
var (
|
||||
searchSchema = "SELECT schema_name FROM [SHOW SCHEMAS] WHERE schema_name = $1"
|
||||
searchTable = "SELECT table_name FROM [SHOW TABLES] WHERE table_name = $1"
|
||||
searchSystemSequence = "SELECT sequence_name FROM [SHOW SEQUENCES] WHERE sequence_name = 'system_seq'"
|
||||
|
||||
//go:embed sql/04_eventstore.sql
|
||||
createEventstoreStmt string
|
||||
//go:embed sql/05_projections.sql
|
||||
createProjectionsStmt string
|
||||
//go:embed sql/06_system.sql
|
||||
createSystemStmt string
|
||||
//go:embed sql/07_encryption_keys_table.sql
|
||||
createEncryptionKeysStmt string
|
||||
//go:embed sql/08_enable_hash_sharded_indexes.sql
|
||||
enableHashShardedIdx string
|
||||
//go:embed sql/09_events_table.sql
|
||||
createEventsStmt string
|
||||
//go:embed sql/10_system_sequence.sql
|
||||
createSystemSequenceStmt string
|
||||
//go:embed sql/11_unique_constraints_table.sql
|
||||
createUniqueConstraints string
|
||||
)
|
||||
|
||||
func newZitadel() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "zitadel",
|
||||
@ -62,44 +40,44 @@ Prereqesits:
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyZitadel(db *sql.DB) error {
|
||||
if err := verify(db, exists(searchSchema, systemSchema), exec(createSystemStmt)); err != nil {
|
||||
func VerifyZitadel(db *sql.DB, config database.Config) error {
|
||||
if err := exec(db, fmt.Sprintf(createSystemStmt, config.Username()), nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verify(db, exists(searchTable, encryptionKeysTable), createEncryptionKeys); err != nil {
|
||||
if err := createEncryptionKeys(db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verify(db, exists(searchSchema, projectionsSchema), exec(createProjectionsStmt)); err != nil {
|
||||
if err := exec(db, fmt.Sprintf(createProjectionsStmt, config.Username()), nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verify(db, exists(searchSchema, eventstoreSchema), exec(createEventstoreStmt)); err != nil {
|
||||
if err := exec(db, fmt.Sprintf(createEventstoreStmt, config.Username()), nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verify(db, exists(searchTable, eventsTable), createEvents); err != nil {
|
||||
if err := createEvents(db); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verify(db, exists(searchSystemSequence), exec(createSystemSequenceStmt)); err != nil {
|
||||
if err := exec(db, createSystemSequenceStmt, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := verify(db, exists(searchTable, uniqueConstraintsTable), exec(createUniqueConstraints)); err != nil {
|
||||
if err := exec(db, createUniqueConstraints, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyZitadel(config database.Config) error {
|
||||
logging.WithFields("database", config.Database).Info("verify zitadel")
|
||||
logging.WithFields("database", config.Database()).Info("verify zitadel")
|
||||
db, err := database.Connect(config, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := VerifyZitadel(db); err != nil {
|
||||
if err := VerifyZitadel(db, config); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -124,10 +102,6 @@ func createEvents(db *sql.DB) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = tx.Exec(enableHashShardedIdx); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = tx.Exec(createEventsStmt); err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -7,6 +7,12 @@ import (
|
||||
)
|
||||
|
||||
func Test_verifyEvents(t *testing.T) {
|
||||
err := ReadStmts("cockroach") //TODO: check all dialects
|
||||
if err != nil {
|
||||
t.Errorf("unable to read stmts: %v", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
type args struct {
|
||||
db db
|
||||
}
|
||||
@ -24,23 +30,11 @@ func Test_verifyEvents(t *testing.T) {
|
||||
},
|
||||
targetErr: sql.ErrConnDone,
|
||||
},
|
||||
{
|
||||
name: "hash sharded indexes fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectBegin(nil),
|
||||
expectExec("SET experimental_enable_hash_sharded_indexes = on", sql.ErrNoRows),
|
||||
expectRollback(nil),
|
||||
),
|
||||
},
|
||||
targetErr: sql.ErrNoRows,
|
||||
},
|
||||
{
|
||||
name: "create table fails",
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectBegin(nil),
|
||||
expectExec("SET experimental_enable_hash_sharded_indexes = on", nil),
|
||||
expectExec(createEventsStmt, sql.ErrNoRows),
|
||||
expectRollback(nil),
|
||||
),
|
||||
@ -52,7 +46,6 @@ func Test_verifyEvents(t *testing.T) {
|
||||
args: args{
|
||||
db: prepareDB(t,
|
||||
expectBegin(nil),
|
||||
expectExec("SET experimental_enable_hash_sharded_indexes = on", nil),
|
||||
expectExec(createEventsStmt, nil),
|
||||
expectCommit(nil),
|
||||
),
|
||||
@ -60,6 +53,7 @@ func Test_verifyEvents(t *testing.T) {
|
||||
targetErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := createEvents(tt.args.db.db); !errors.Is(err, tt.targetErr) {
|
||||
|
@ -11,8 +11,6 @@ var (
|
||||
createAdminViews string
|
||||
//go:embed 01_sql/auth.sql
|
||||
createAuthViews string
|
||||
//go:embed 01_sql/notification.sql
|
||||
createNotificationViews string
|
||||
//go:embed 01_sql/projections.sql
|
||||
createProjections string
|
||||
)
|
||||
@ -22,7 +20,7 @@ type ProjectionTable struct {
|
||||
}
|
||||
|
||||
func (mig *ProjectionTable) Execute(ctx context.Context) error {
|
||||
stmt := createAdminViews + createAuthViews + createNotificationViews + createProjections
|
||||
stmt := createAdminViews + createAuthViews + createProjections
|
||||
_, err := mig.dbClient.ExecContext(ctx, stmt)
|
||||
return err
|
||||
}
|
||||
|
@ -30,28 +30,28 @@ CREATE TABLE adminapi.failed_events (
|
||||
);
|
||||
|
||||
CREATE TABLE adminapi.styling (
|
||||
aggregate_id STRING NOT NULL,
|
||||
aggregate_id TEXT NOT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
label_policy_state INT2 NOT NULL DEFAULT 0:::INT2,
|
||||
label_policy_state INT2 NOT NULL DEFAULT 0::INT2,
|
||||
sequence INT8 NULL,
|
||||
primary_color STRING NULL,
|
||||
background_color STRING NULL,
|
||||
warn_color STRING NULL,
|
||||
font_color STRING NULL,
|
||||
primary_color_dark STRING NULL,
|
||||
background_color_dark STRING NULL,
|
||||
warn_color_dark STRING NULL,
|
||||
font_color_dark STRING NULL,
|
||||
logo_url STRING NULL,
|
||||
icon_url STRING NULL,
|
||||
logo_dark_url STRING NULL,
|
||||
icon_dark_url STRING NULL,
|
||||
font_url STRING NULL,
|
||||
primary_color TEXT NULL,
|
||||
background_color TEXT NULL,
|
||||
warn_color TEXT NULL,
|
||||
font_color TEXT NULL,
|
||||
primary_color_dark TEXT NULL,
|
||||
background_color_dark TEXT NULL,
|
||||
warn_color_dark TEXT NULL,
|
||||
font_color_dark TEXT NULL,
|
||||
logo_url TEXT NULL,
|
||||
icon_url TEXT NULL,
|
||||
logo_dark_url TEXT NULL,
|
||||
icon_dark_url TEXT NULL,
|
||||
font_url TEXT NULL,
|
||||
err_msg_popup BOOL NULL,
|
||||
disable_watermark BOOL NULL,
|
||||
hide_login_name_suffix BOOL NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (aggregate_id, label_policy_state, instance_id)
|
||||
);
|
||||
|
@ -30,48 +30,48 @@ CREATE TABLE auth.failed_events (
|
||||
);
|
||||
|
||||
CREATE TABLE auth.users (
|
||||
id STRING NULL,
|
||||
id TEXT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
resource_owner STRING NULL,
|
||||
resource_owner TEXT NULL,
|
||||
user_state INT2 NULL,
|
||||
password_set BOOL NULL,
|
||||
password_change_required BOOL NULL,
|
||||
password_change TIMESTAMPTZ NULL,
|
||||
last_login TIMESTAMPTZ NULL,
|
||||
user_name STRING NULL,
|
||||
login_names STRING[] NULL,
|
||||
preferred_login_name STRING NULL,
|
||||
first_name STRING NULL,
|
||||
last_name STRING NULL,
|
||||
nick_name STRING NULL,
|
||||
display_name STRING NULL,
|
||||
preferred_language STRING NULL,
|
||||
user_name TEXT NULL,
|
||||
login_names TEXT[] NULL,
|
||||
preferred_login_name TEXT NULL,
|
||||
first_name TEXT NULL,
|
||||
last_name TEXT NULL,
|
||||
nick_name TEXT NULL,
|
||||
display_name TEXT NULL,
|
||||
preferred_language TEXT NULL,
|
||||
gender INT2 NULL,
|
||||
email STRING NULL,
|
||||
email TEXT NULL,
|
||||
is_email_verified BOOL NULL,
|
||||
phone STRING NULL,
|
||||
phone TEXT NULL,
|
||||
is_phone_verified BOOL NULL,
|
||||
country STRING NULL,
|
||||
locality STRING NULL,
|
||||
postal_code STRING NULL,
|
||||
region STRING NULL,
|
||||
street_address STRING NULL,
|
||||
country TEXT NULL,
|
||||
locality TEXT NULL,
|
||||
postal_code TEXT NULL,
|
||||
region TEXT NULL,
|
||||
street_address TEXT NULL,
|
||||
otp_state INT2 NULL,
|
||||
mfa_max_set_up INT2 NULL,
|
||||
mfa_init_skipped TIMESTAMPTZ NULL,
|
||||
sequence INT8 NULL,
|
||||
init_required BOOL NULL,
|
||||
username_change_required BOOL NULL,
|
||||
machine_name STRING NULL,
|
||||
machine_description STRING NULL,
|
||||
user_type STRING NULL,
|
||||
u2f_tokens BYTES NULL,
|
||||
passwordless_tokens BYTES NULL,
|
||||
avatar_key STRING NULL,
|
||||
machine_name TEXT NULL,
|
||||
machine_description TEXT NULL,
|
||||
user_type TEXT NULL,
|
||||
u2f_tokens BYTEA NULL,
|
||||
passwordless_tokens BYTEA NULL,
|
||||
avatar_key TEXT NULL,
|
||||
passwordless_init_required BOOL NULL,
|
||||
password_init_required BOOL NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (id, instance_id)
|
||||
);
|
||||
@ -79,148 +79,151 @@ CREATE TABLE auth.users (
|
||||
CREATE TABLE auth.user_sessions (
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
resource_owner STRING NULL,
|
||||
resource_owner TEXT NULL,
|
||||
state INT2 NULL,
|
||||
user_agent_id STRING NULL,
|
||||
user_id STRING NULL,
|
||||
user_name STRING NULL,
|
||||
user_agent_id TEXT NULL,
|
||||
user_id TEXT NULL,
|
||||
user_name TEXT NULL,
|
||||
password_verification TIMESTAMPTZ NULL,
|
||||
second_factor_verification TIMESTAMPTZ NULL,
|
||||
multi_factor_verification TIMESTAMPTZ NULL,
|
||||
sequence INT8 NULL,
|
||||
second_factor_verification_type INT2 NULL,
|
||||
multi_factor_verification_type INT2 NULL,
|
||||
user_display_name STRING NULL,
|
||||
login_name STRING NULL,
|
||||
user_display_name TEXT NULL,
|
||||
login_name TEXT NULL,
|
||||
external_login_verification TIMESTAMPTZ NULL,
|
||||
selected_idp_config_id STRING NULL,
|
||||
selected_idp_config_id TEXT NULL,
|
||||
passwordless_verification TIMESTAMPTZ NULL,
|
||||
avatar_key STRING NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
avatar_key TEXT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (user_agent_id, user_id, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE auth.user_external_idps (
|
||||
external_user_id STRING NOT NULL,
|
||||
idp_config_id STRING NOT NULL,
|
||||
user_id STRING NULL,
|
||||
idp_name STRING NULL,
|
||||
user_display_name STRING NULL,
|
||||
external_user_id TEXT NOT NULL,
|
||||
idp_config_id TEXT NOT NULL,
|
||||
user_id TEXT NULL,
|
||||
idp_name TEXT NULL,
|
||||
user_display_name TEXT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
sequence INT8 NULL,
|
||||
resource_owner STRING NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
resource_owner TEXT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (external_user_id, idp_config_id, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE auth.tokens (
|
||||
id STRING NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
resource_owner STRING NULL,
|
||||
application_id STRING NULL,
|
||||
user_agent_id STRING NULL,
|
||||
user_id STRING NULL,
|
||||
resource_owner TEXT NULL,
|
||||
application_id TEXT NULL,
|
||||
user_agent_id TEXT NULL,
|
||||
user_id TEXT NULL,
|
||||
expiration TIMESTAMPTZ NULL,
|
||||
sequence INT8 NULL,
|
||||
scopes STRING[] NULL,
|
||||
audience STRING[] NULL,
|
||||
preferred_language STRING NULL,
|
||||
refresh_token_id STRING NULL,
|
||||
scopes TEXT[] NULL,
|
||||
audience TEXT[] NULL,
|
||||
preferred_language TEXT NULL,
|
||||
refresh_token_id TEXT NULL,
|
||||
is_pat BOOL NOT NULL DEFAULT false,
|
||||
instance_id STRING NOT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (id, instance_id),
|
||||
INDEX user_user_agent_idx (user_id, user_agent_id)
|
||||
PRIMARY KEY (id, instance_id)
|
||||
);
|
||||
|
||||
CREATE INDEX user_user_agent_idx ON auth.tokens (user_id, user_agent_id);
|
||||
|
||||
CREATE TABLE auth.refresh_tokens (
|
||||
id STRING NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
resource_owner STRING NULL,
|
||||
token STRING NULL,
|
||||
client_id STRING NOT NULL,
|
||||
user_agent_id STRING NOT NULL,
|
||||
user_id STRING NOT NULL,
|
||||
resource_owner TEXT NULL,
|
||||
token TEXT NULL,
|
||||
client_id TEXT NOT NULL,
|
||||
user_agent_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
auth_time TIMESTAMPTZ NULL,
|
||||
idle_expiration TIMESTAMPTZ NULL,
|
||||
expiration TIMESTAMPTZ NULL,
|
||||
sequence INT8 NULL,
|
||||
scopes STRING[] NULL,
|
||||
audience STRING[] NULL,
|
||||
amr STRING[] NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
scopes TEXT[] NULL,
|
||||
audience TEXT[] NULL,
|
||||
amr TEXT[] NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (id, instance_id),
|
||||
UNIQUE INDEX unique_client_user_index (client_id, user_agent_id, user_id)
|
||||
PRIMARY KEY (id, instance_id)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX unique_client_user_index ON auth.refresh_tokens (client_id, user_agent_id, user_id);
|
||||
|
||||
CREATE TABLE auth.org_project_mapping (
|
||||
org_id STRING NOT NULL,
|
||||
project_id STRING NOT NULL,
|
||||
project_grant_id STRING NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
org_id TEXT NOT NULL,
|
||||
project_id TEXT NOT NULL,
|
||||
project_grant_id TEXT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (org_id, project_id, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE auth.idp_providers (
|
||||
aggregate_id STRING NOT NULL,
|
||||
idp_config_id STRING NOT NULL,
|
||||
aggregate_id TEXT NOT NULL,
|
||||
idp_config_id TEXT NOT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
sequence INT8 NULL,
|
||||
name STRING NULL,
|
||||
name TEXT NULL,
|
||||
idp_config_type INT2 NULL,
|
||||
idp_provider_type INT2 NULL,
|
||||
idp_state INT2 NULL,
|
||||
styling_type INT2 NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (aggregate_id, idp_config_id, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE auth.idp_configs (
|
||||
idp_config_id STRING NOT NULL,
|
||||
idp_config_id TEXT NOT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
sequence INT8 NULL,
|
||||
aggregate_id STRING NULL,
|
||||
name STRING NULL,
|
||||
aggregate_id TEXT NULL,
|
||||
name TEXT NULL,
|
||||
idp_state INT2 NULL,
|
||||
idp_provider_type INT2 NULL,
|
||||
is_oidc BOOL NULL,
|
||||
oidc_client_id STRING NULL,
|
||||
oidc_client_id TEXT NULL,
|
||||
oidc_client_secret JSONB NULL,
|
||||
oidc_issuer STRING NULL,
|
||||
oidc_scopes STRING[] NULL,
|
||||
oidc_issuer TEXT NULL,
|
||||
oidc_scopes TEXT[] NULL,
|
||||
oidc_idp_display_name_mapping INT2 NULL,
|
||||
oidc_idp_username_mapping INT2 NULL,
|
||||
styling_type INT2 NULL,
|
||||
oauth_authorization_endpoint STRING NULL,
|
||||
oauth_token_endpoint STRING NULL,
|
||||
oauth_authorization_endpoint TEXT NULL,
|
||||
oauth_token_endpoint TEXT NULL,
|
||||
auto_register BOOL NULL,
|
||||
jwt_endpoint STRING NULL,
|
||||
jwt_keys_endpoint STRING NULL,
|
||||
jwt_header_name STRING NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
jwt_endpoint TEXT NULL,
|
||||
jwt_keys_endpoint TEXT NULL,
|
||||
jwt_header_name TEXT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (idp_config_id, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE auth.auth_requests (
|
||||
id STRING NOT NULL,
|
||||
id TEXT NOT NULL,
|
||||
request JSONB NULL,
|
||||
code STRING NULL,
|
||||
code TEXT NULL,
|
||||
request_type INT2 NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
instance_id STRING NOT NULL,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (id, instance_id),
|
||||
INDEX auth_code_idx (code)
|
||||
PRIMARY KEY (id, instance_id)
|
||||
);
|
||||
|
||||
CREATE INDEX auth_code_idx ON auth.auth_requests (code);
|
||||
|
@ -1,55 +0,0 @@
|
||||
CREATE SCHEMA notification;
|
||||
|
||||
CREATE TABLE notification.locks (
|
||||
locker_id TEXT,
|
||||
locked_until TIMESTAMPTZ(3),
|
||||
view_name TEXT,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (view_name, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE notification.current_sequences (
|
||||
view_name TEXT,
|
||||
current_sequence BIGINT,
|
||||
event_timestamp TIMESTAMPTZ,
|
||||
last_successful_spooler_run TIMESTAMPTZ,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (view_name, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE notification.failed_events (
|
||||
view_name TEXT,
|
||||
failed_sequence BIGINT,
|
||||
failure_count SMALLINT,
|
||||
err_msg TEXT,
|
||||
instance_id TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (view_name, failed_sequence, instance_id)
|
||||
);
|
||||
|
||||
CREATE TABLE notification.notify_users (
|
||||
id STRING NOT NULL,
|
||||
creation_date TIMESTAMPTZ NULL,
|
||||
change_date TIMESTAMPTZ NULL,
|
||||
resource_owner STRING NULL,
|
||||
user_name STRING NULL,
|
||||
first_name STRING NULL,
|
||||
last_name STRING NULL,
|
||||
nick_name STRING NULL,
|
||||
display_name STRING NULL,
|
||||
preferred_language STRING NULL,
|
||||
gender INT2 NULL,
|
||||
last_email STRING NULL,
|
||||
verified_email STRING NULL,
|
||||
last_phone STRING NULL,
|
||||
verified_phone STRING NULL,
|
||||
sequence INT8 NULL,
|
||||
password_set BOOL NULL,
|
||||
login_names STRING NULL,
|
||||
preferred_login_name STRING NULL,
|
||||
instance_id STRING NULL,
|
||||
|
||||
PRIMARY KEY (id)
|
||||
);
|
@ -13,8 +13,8 @@ CREATE TABLE system.assets (
|
||||
resource_owner TEXT,
|
||||
name TEXT,
|
||||
content_type TEXT,
|
||||
hash TEXT AS (md5(data)) STORED,
|
||||
data BYTES,
|
||||
hash TEXT GENERATED ALWAYS AS (md5(data)) STORED,
|
||||
data BYTEA,
|
||||
updated_at TIMESTAMPTZ,
|
||||
|
||||
PRIMARY KEY (instance_id, resource_owner, name)
|
||||
|
47
cmd/start/start_from_setup.go
Normal file
47
cmd/start/start_from_setup.go
Normal file
@ -0,0 +1,47 @@
|
||||
package start
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/cmd/key"
|
||||
"github.com/zitadel/zitadel/cmd/setup"
|
||||
"github.com/zitadel/zitadel/cmd/tls"
|
||||
)
|
||||
|
||||
func NewStartFromSetup() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "start-from-setup",
|
||||
Short: "cold starts zitadel",
|
||||
Long: `cold starts ZITADEL.
|
||||
First the initial events are created.
|
||||
Last ZITADEL starts.
|
||||
|
||||
Requirements:
|
||||
- database
|
||||
- database is initialized
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := tls.ModeFromFlag(cmd)
|
||||
logging.OnError(err).Fatal("invalid tlsMode")
|
||||
|
||||
masterKey, err := key.MasterKey(cmd)
|
||||
logging.OnError(err).Panic("No master key provided")
|
||||
|
||||
setupConfig := setup.MustNewConfig(viper.GetViper())
|
||||
setupSteps := setup.MustNewSteps(viper.New())
|
||||
setup.Setup(setupConfig, setupSteps, masterKey)
|
||||
|
||||
startConfig := MustNewConfig(viper.GetViper())
|
||||
|
||||
err = startZitadel(startConfig, masterKey)
|
||||
logging.OnError(err).Fatal("unable to start zitadel")
|
||||
},
|
||||
}
|
||||
|
||||
startFlags(cmd)
|
||||
setup.Flags(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
@ -51,6 +51,7 @@ func New(out io.Writer, in io.Reader, args []string) *cobra.Command {
|
||||
setup.New(),
|
||||
start.New(),
|
||||
start.NewStartFromInit(),
|
||||
start.NewStartFromSetup(),
|
||||
key.New(),
|
||||
)
|
||||
|
||||
|
@ -144,4 +144,4 @@ The storage layer of ZITADEL is responsible for multiple things. For example:
|
||||
- Backup and restore operation for disaster recovery purpose
|
||||
|
||||
ZITADEL currently supports CockroachDB as first choice of storage due to its perfect match for ZITADELs needs.
|
||||
Postgresql support is work in progress and should be available soon as well.
|
||||
Postgresql support is currently in beta.
|
||||
|
@ -10,7 +10,7 @@ Since the storage layer takes the heavy lifting of making sure that data in sync
|
||||
Depending on your projects needs our general recommendation is to run ZITADEL and ZITADELs storage layer across multiple availability zones in the same region or if you need higher guarantees run the storage layer across multiple regions.
|
||||
Consult the [CockroachDB documentation](https://www.cockroachlabs.com/docs/) for more details or use the [CockroachCloud Service](https://www.cockroachlabs.com/docs/cockroachcloud/create-an-account.html)
|
||||
|
||||
> Soon ZITADEL will also support Postgres as database.
|
||||
> Postgres support of ZITADEL is currently in beta.
|
||||
|
||||
## Scalability
|
||||
|
||||
|
@ -8,19 +8,19 @@ services:
|
||||
image: 'ghcr.io/zitadel/zitadel:stable'
|
||||
command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled'
|
||||
environment:
|
||||
- 'ZITADEL_DATABASE_COCKROACH_HOST=db'
|
||||
- 'ZITADEL_DATABASE_COCKROACH_HOST=crdb'
|
||||
- 'ZITADEL_EXTERNALSECURE=false'
|
||||
depends_on:
|
||||
db:
|
||||
crdb:
|
||||
condition: 'service_healthy'
|
||||
ports:
|
||||
- '8080:8080'
|
||||
|
||||
db:
|
||||
crdb:
|
||||
restart: 'always'
|
||||
networks:
|
||||
- 'zitadel'
|
||||
image: 'cockroachdb/cockroach:v22.1.0'
|
||||
image: 'cockroachdb/cockroach:v22.1.3'
|
||||
command: 'start-single-node --insecure'
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health?ready=1"]
|
||||
|
@ -15,7 +15,7 @@ By default, it runs a highly available ZITADEL instance along with a secure and
|
||||
## Prerequisits
|
||||
|
||||
- ZITADEL does not need many resources, 1 CPU and 512MB memory are more than enough. (With more CPU, the password hashing might be faster)
|
||||
- A cockroachDB or [🚧 Postgresql coming soon](https://github.com/zitadel/zitadel/pull/3998) as only needed storage
|
||||
- A cockroachDB or Postgresql (currently in beta) as only needed storage
|
||||
- If you want to front ZITADEL with a reverse proxy, web application firewall or content delivery network, make sure to support [HTTP/2](../manage/self-hosted/http2)
|
||||
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
## Cockroach
|
||||
|
||||
The default database of ZITADEL is [CockroachDB](https://www.cockroachlabs.com). The SQL database provides a bunch of features like horizontal scalability, data reginality and many more.
|
||||
|
||||
The default configuration of the database looks like this:
|
||||
```yaml
|
||||
Database:
|
||||
cockroach:
|
||||
Host: localhost
|
||||
Port: 26257
|
||||
Database: zitadel
|
||||
MaxOpenConns: 20
|
||||
MaxConnLifetime: 30m
|
||||
MaxConnIdleTime: 30m
|
||||
Options: ""
|
||||
User:
|
||||
Username: zitadel
|
||||
Password: ""
|
||||
SSL:
|
||||
Mode: disable
|
||||
RootCert: ""
|
||||
Cert: ""
|
||||
Key: ""
|
||||
Admin:
|
||||
Username: root
|
||||
Password: ""
|
||||
SSL:
|
||||
Mode: disable
|
||||
RootCert: ""
|
||||
Cert: ""
|
||||
Key: ""
|
||||
```
|
36
docs/docs/guides/manage/self-hosted/database/_postgres.mdx
Normal file
36
docs/docs/guides/manage/self-hosted/database/_postgres.mdx
Normal file
@ -0,0 +1,36 @@
|
||||
## Postgres
|
||||
|
||||
:::caution
|
||||
Postgres extension is currently in beta.
|
||||
:::
|
||||
|
||||
If you want to use a Postgres database instead of CockroachDB you can [overwrite the default configuration](../configure/configure.mdx).
|
||||
|
||||
Postgres can be configured as follows:
|
||||
```yaml
|
||||
Database:
|
||||
postgres:
|
||||
Host: localhost
|
||||
Port: 5432
|
||||
Database: zitadel
|
||||
MaxOpenConns: 25
|
||||
MaxConnLifetime: 1h
|
||||
MaxConnIdleTime: 5m
|
||||
Options:
|
||||
User:
|
||||
Username: zitadel
|
||||
Password: zitadel
|
||||
SSL:
|
||||
Mode: disable
|
||||
RootCert:
|
||||
Cert:
|
||||
Key:
|
||||
Admin:
|
||||
Username: postgres
|
||||
Password: postgres
|
||||
SSL:
|
||||
Mode: disable
|
||||
RootCert:
|
||||
Cert:
|
||||
Key:
|
||||
```
|
28
docs/docs/guides/manage/self-hosted/database/database.mdx
Normal file
28
docs/docs/guides/manage/self-hosted/database/database.mdx
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Database
|
||||
---
|
||||
|
||||
import Tabs from "@theme/Tabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
import Cockroach from './_cockroachdb.mdx'
|
||||
import Postgres from './_postgres.mdx'
|
||||
|
||||
# Database Configuration
|
||||
|
||||
<Tabs
|
||||
groupId="database-vendor"
|
||||
default="cockroach"
|
||||
values={[
|
||||
{'label': 'Cockroach', 'value': 'crdb'},
|
||||
{'label': 'Postgres', 'value': 'pg'},
|
||||
]}
|
||||
>
|
||||
<TabItem value="crdb">
|
||||
<Cockroach/>
|
||||
<More/>
|
||||
</TabItem>
|
||||
<TabItem value="pg">
|
||||
<Postgres/>
|
||||
<More/>
|
||||
</TabItem>
|
||||
</Tabs>
|
@ -86,6 +86,7 @@ module.exports = {
|
||||
"guides/manage/self-hosted/custom-domain",
|
||||
"guides/manage/self-hosted/http2",
|
||||
"guides/manage/self-hosted/tls_modes",
|
||||
"guides/manage/self-hosted/database/database",
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -95,7 +96,6 @@ module.exports = {
|
||||
"guides/manage/console/organizations",
|
||||
"guides/manage/console/projects",
|
||||
"guides/manage/console/applications",
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
|
16
go.mod
16
go.mod
@ -1,6 +1,6 @@
|
||||
module github.com/zitadel/zitadel
|
||||
|
||||
go 1.17
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.14.0
|
||||
@ -29,6 +29,9 @@ require (
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.1
|
||||
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/jinzhu/gorm v1.9.16
|
||||
github.com/k3a/html2text v1.0.8
|
||||
github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73
|
||||
@ -66,7 +69,7 @@ require (
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/tools v0.1.8
|
||||
golang.org/x/tools v0.1.11
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
|
||||
google.golang.org/grpc v1.43.0
|
||||
google.golang.org/protobuf v1.27.1
|
||||
@ -115,7 +118,7 @@ require (
|
||||
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/go-cmp v0.5.6 // indirect
|
||||
github.com/google/go-cmp v0.5.8 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
@ -125,6 +128,11 @@ require (
|
||||
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/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/jarcoal/jpath v0.0.0-20140328210829-f76b8b2dbf52
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
@ -169,7 +177,7 @@ require (
|
||||
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.5.1 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/api v0.63.0
|
||||
|
58
go.sum
58
go.sum
@ -69,6 +69,8 @@ github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJ
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Masterminds/squirrel v1.5.2 h1:UiOEi2ZX4RCSkpiNDQN5kro/XIBpSRk9iTqdIRPzUXE=
|
||||
@ -117,7 +119,6 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW
|
||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
||||
@ -125,7 +126,6 @@ github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInq
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
@ -151,6 +151,7 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 h1:KwaoQzs/WeUxxJqiJsZ4euOly1Az/IgZXXSxlD/UBNk=
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.4 h1:VuiBJKut2Imgrzl+TNk+U5+GxLOh3hnIFxU0EzjTCnI=
|
||||
github.com/cockroachdb/cockroach-go/v2 v2.2.4/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI=
|
||||
@ -263,13 +264,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
|
||||
@ -362,8 +360,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@ -391,7 +390,6 @@ github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@ -436,7 +434,6 @@ github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4=
|
||||
github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
|
||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
|
||||
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@ -490,6 +487,7 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
|
||||
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
|
||||
@ -498,8 +496,17 @@ github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5
|
||||
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
|
||||
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
|
||||
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
|
||||
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
|
||||
github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8=
|
||||
github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
|
||||
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
|
||||
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
|
||||
@ -508,7 +515,11 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
|
||||
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
|
||||
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y=
|
||||
github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
|
||||
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
|
||||
@ -517,6 +528,9 @@ github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4
|
||||
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
|
||||
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
|
||||
github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
|
||||
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
|
||||
github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs=
|
||||
github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
|
||||
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
|
||||
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
|
||||
@ -524,11 +538,15 @@ github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXg
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
|
||||
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
|
||||
github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA=
|
||||
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
|
||||
github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y=
|
||||
github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ=
|
||||
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||
github.com/jarcoal/jpath v0.0.0-20140328210829-f76b8b2dbf52 h1:jny9eqYPwkG8IVy7foUoRjQmFLcArCSz+uPsL6KS0HQ=
|
||||
github.com/jarcoal/jpath v0.0.0-20140328210829-f76b8b2dbf52/go.mod h1:RDZ+4PR3mDOtTpVbI0qBE+rdhmtIrtbssiNn38/1OWA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
@ -570,7 +588,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
|
||||
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
@ -596,13 +613,13 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
@ -779,13 +796,13 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
|
||||
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
@ -864,7 +881,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/zitadel/logging v0.3.4 h1:9hZsTjMMTE3X2LUi0xcF9Q9EdLo+FAezeu52ireBbHM=
|
||||
github.com/zitadel/logging v0.3.4/go.mod h1:aPpLQhE+v6ocNK0TWrBrd363hZ95KcI17Q1ixAQwZF0=
|
||||
@ -953,9 +969,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
@ -999,8 +1017,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -1054,8 +1072,6 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba h1:6u6sik+bn/y7vILcYkK3iwTBWN7WtBvB0+SZswQnbf8=
|
||||
golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -1168,17 +1184,14 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -1257,8 +1270,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
|
||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
|
||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -1446,7 +1459,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
|
||||
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
@ -130,7 +130,7 @@ func OIDCGrantTypesFromModel(grantTypes []domain.OIDCGrantType) []app_pb.OIDCGra
|
||||
}
|
||||
|
||||
func OIDCGrantTypesToDomain(grantTypes []app_pb.OIDCGrantType) []domain.OIDCGrantType {
|
||||
if grantTypes == nil || len(grantTypes) == 0 {
|
||||
if len(grantTypes) == 0 {
|
||||
return []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode}
|
||||
}
|
||||
oidcGrantTypes := make([]domain.OIDCGrantType, len(grantTypes))
|
||||
|
@ -6,9 +6,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
//sql import
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
@ -61,13 +58,15 @@ func (c *Config) Decode(configs []interface{}) (dialect.Connector, error) {
|
||||
}
|
||||
|
||||
func (c *Config) Connect(useAdmin bool) (*sql.DB, error) {
|
||||
client, err := sql.Open("postgres", c.String(useAdmin))
|
||||
client, err := sql.Open("pgx", c.String(useAdmin))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client.SetMaxOpenConns(int(c.MaxOpenConns))
|
||||
client.SetConnMaxLifetime(c.MaxConnLifetime)
|
||||
client.SetConnMaxIdleTime(c.MaxConnIdleTime)
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
|
||||
_ "github.com/zitadel/zitadel/internal/database/cockroach"
|
||||
"github.com/zitadel/zitadel/internal/database/dialect"
|
||||
_ "github.com/zitadel/zitadel/internal/database/postgres"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@ -17,23 +19,6 @@ func (c *Config) SetConnector(connector dialect.Connector) {
|
||||
c.connector = connector
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string
|
||||
Password string
|
||||
SSL SSL
|
||||
}
|
||||
|
||||
type SSL struct {
|
||||
// type of connection security
|
||||
Mode string
|
||||
// RootCert Path to the CA certificate
|
||||
RootCert string
|
||||
// Cert Path to the client certificate
|
||||
Cert string
|
||||
// Key Path to the client private key
|
||||
Key string
|
||||
}
|
||||
|
||||
func Connect(config Config, useAdmin bool) (*sql.DB, error) {
|
||||
client, err := config.connector.Connect(useAdmin)
|
||||
if err != nil {
|
||||
@ -41,7 +26,7 @@ func Connect(config Config, useAdmin bool) (*sql.DB, error) {
|
||||
}
|
||||
|
||||
if err := client.Ping(); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.ThrowPreconditionFailed(err, "DATAB-0pIWD", "Errors.Database.Connection.Failed")
|
||||
}
|
||||
|
||||
return client, nil
|
||||
|
153
internal/database/postgres/config.go
Normal file
153
internal/database/postgres/config.go
Normal file
@ -0,0 +1,153 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/zitadel/internal/database/dialect"
|
||||
)
|
||||
|
||||
const (
|
||||
sslDisabledMode = "disable"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Host string
|
||||
Port int32
|
||||
Database string
|
||||
MaxOpenConns uint32
|
||||
MaxConnLifetime time.Duration
|
||||
MaxConnIdleTime time.Duration
|
||||
User User
|
||||
Admin User
|
||||
|
||||
//Additional options to be appended as options=<Options>
|
||||
//The value will be taken as is. Multiple options are space separated.
|
||||
Options string
|
||||
}
|
||||
|
||||
func (c *Config) MatchName(name string) bool {
|
||||
for _, key := range []string{"pg", "postgres"} {
|
||||
if strings.TrimSpace(strings.ToLower(name)) == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Config) Decode(configs []interface{}) (dialect.Connector, error) {
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
|
||||
Result: c,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, config := range configs {
|
||||
if err = decoder.Decode(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Config) Connect(useAdmin bool) (*sql.DB, error) {
|
||||
logging.Warn("postgres is currently in beta")
|
||||
db, err := sql.Open("pgx", c.String(useAdmin))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db.SetMaxOpenConns(int(c.MaxOpenConns))
|
||||
db.SetConnMaxLifetime(c.MaxConnLifetime)
|
||||
db.SetConnMaxIdleTime(c.MaxConnIdleTime)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (c *Config) DatabaseName() string {
|
||||
return c.Database
|
||||
}
|
||||
|
||||
func (c *Config) Username() string {
|
||||
return c.User.Username
|
||||
}
|
||||
|
||||
func (c *Config) Password() string {
|
||||
return c.User.Password
|
||||
}
|
||||
|
||||
func (c *Config) Type() string {
|
||||
return "postgres"
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string
|
||||
Password string
|
||||
SSL SSL
|
||||
}
|
||||
|
||||
type SSL struct {
|
||||
// type of connection security
|
||||
Mode string
|
||||
// RootCert Path to the CA certificate
|
||||
RootCert string
|
||||
// Cert Path to the client certificate
|
||||
Cert string
|
||||
// Key Path to the client private key
|
||||
Key string
|
||||
}
|
||||
|
||||
func (s *Config) checkSSL(user User) {
|
||||
if user.SSL.Mode == sslDisabledMode || user.SSL.Mode == "" {
|
||||
user.SSL = SSL{Mode: sslDisabledMode}
|
||||
return
|
||||
}
|
||||
if user.SSL.RootCert == "" {
|
||||
logging.WithFields(
|
||||
"cert set", user.SSL.Cert != "",
|
||||
"key set", user.SSL.Key != "",
|
||||
"rootCert set", user.SSL.RootCert != "",
|
||||
).Fatal("at least ssl root cert has to be set")
|
||||
}
|
||||
}
|
||||
|
||||
func (c Config) String(useAdmin bool) string {
|
||||
user := c.User
|
||||
if useAdmin {
|
||||
user = c.Admin
|
||||
}
|
||||
c.checkSSL(user)
|
||||
fields := []string{
|
||||
"host=" + c.Host,
|
||||
"port=" + strconv.Itoa(int(c.Port)),
|
||||
"user=" + user.Username,
|
||||
"application_name=zitadel",
|
||||
"sslmode=" + user.SSL.Mode,
|
||||
}
|
||||
if c.Options != "" {
|
||||
fields = append(fields, "options="+c.Options)
|
||||
}
|
||||
if user.Password != "" {
|
||||
fields = append(fields, "password="+user.Password)
|
||||
}
|
||||
if !useAdmin {
|
||||
fields = append(fields, "dbname="+c.Database)
|
||||
}
|
||||
if user.SSL.Mode != sslDisabledMode {
|
||||
fields = append(fields, "sslrootcert="+user.SSL.RootCert)
|
||||
if user.SSL.Cert != "" {
|
||||
fields = append(fields, "sslcert="+user.SSL.Cert)
|
||||
}
|
||||
if user.SSL.Key != "" {
|
||||
fields = append(fields, "sslkey="+user.SSL.Key)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(fields, " ")
|
||||
}
|
14
internal/database/postgres/pg.go
Normal file
14
internal/database/postgres/pg.go
Normal file
@ -0,0 +1,14 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
|
||||
//sql import
|
||||
_ "github.com/jackc/pgx/v4/stdlib"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database/dialect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
config := &Config{}
|
||||
dialect.Register(config, config, false)
|
||||
}
|
72
internal/database/type.go
Normal file
72
internal/database/type.go
Normal file
@ -0,0 +1,72 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
|
||||
"github.com/jackc/pgtype"
|
||||
)
|
||||
|
||||
type StringArray []string
|
||||
|
||||
// Scan implements the `database/sql.Scanner` interface.
|
||||
func (s *StringArray) Scan(src any) error {
|
||||
array := new(pgtype.TextArray)
|
||||
if err := array.Scan(src); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := array.AssignTo(s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the `database/sql/driver.Valuer`` interface.
|
||||
func (s StringArray) Value() (driver.Value, error) {
|
||||
if len(s) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
array := pgtype.TextArray{}
|
||||
if err := array.Set(s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return array.Value()
|
||||
}
|
||||
|
||||
type enumField interface {
|
||||
~int8 | ~uint8 | ~int16 | ~uint16 | ~int32 | ~uint32
|
||||
}
|
||||
|
||||
type EnumArray[F enumField] []F
|
||||
|
||||
// Scan implements the `database/sql.Scanner` interface.
|
||||
func (s *EnumArray[F]) Scan(src any) error {
|
||||
array := new(pgtype.Int2Array)
|
||||
if err := array.Scan(src); err != nil {
|
||||
return err
|
||||
}
|
||||
ints := make([]int32, 0, len(array.Elements))
|
||||
if err := array.AssignTo(&ints); err != nil {
|
||||
return err
|
||||
}
|
||||
*s = make([]F, len(ints))
|
||||
for i, a := range ints {
|
||||
(*s)[i] = F(a)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the `database/sql/driver.Valuer`` interface.
|
||||
func (s EnumArray[F]) Value() (driver.Value, error) {
|
||||
if len(s) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
array := pgtype.Int2Array{}
|
||||
if err := array.Set(s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return array.Value()
|
||||
}
|
@ -6,15 +6,15 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
const (
|
||||
currentSequenceStmtFormat = `SELECT current_sequence, aggregate_type, instance_id FROM %s WHERE projection_name = $1 AND instance_id = ANY ($2) FOR UPDATE`
|
||||
updateCurrentSequencesStmtFormat = `UPSERT INTO %s (projection_name, aggregate_type, current_sequence, instance_id, timestamp) VALUES `
|
||||
updateCurrentSequencesStmtFormat = `INSERT INTO %s (projection_name, aggregate_type, current_sequence, instance_id, timestamp) VALUES `
|
||||
updateCurrentSequencesConflictStmt = ` ON CONFLICT (projection_name, aggregate_type, instance_id) DO UPDATE SET current_sequence = EXCLUDED.current_sequence, timestamp = EXCLUDED.timestamp`
|
||||
)
|
||||
|
||||
type currentSequences map[eventstore.AggregateType][]*instanceSequence
|
||||
@ -24,8 +24,8 @@ type instanceSequence struct {
|
||||
sequence uint64
|
||||
}
|
||||
|
||||
func (h *StatementHandler) currentSequences(ctx context.Context, query func(context.Context, string, ...interface{}) (*sql.Rows, error), instanceIDs []string) (currentSequences, error) {
|
||||
rows, err := query(ctx, h.currentSequenceStmt, h.ProjectionName, pq.StringArray(instanceIDs))
|
||||
func (h *StatementHandler) currentSequences(ctx context.Context, query func(context.Context, string, ...interface{}) (*sql.Rows, error), instanceIDs database.StringArray) (currentSequences, error) {
|
||||
rows, err := query(ctx, h.currentSequenceStmt, h.ProjectionName, instanceIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -74,7 +74,7 @@ func (h *StatementHandler) updateCurrentSequences(tx *sql.Tx, sequences currentS
|
||||
}
|
||||
}
|
||||
|
||||
res, err := tx.Exec(h.updateSequencesBaseStmt+strings.Join(valueQueries, ", "), values...)
|
||||
res, err := tx.Exec(h.updateSequencesBaseStmt+strings.Join(valueQueries, ", ")+updateCurrentSequencesConflictStmt, values...)
|
||||
if err != nil {
|
||||
return errors.ThrowInternal(err, "CRDB-TrH2Z", "unable to exec update sequence")
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
@ -17,7 +17,7 @@ type mockExpectation func(sqlmock.Sqlmock)
|
||||
|
||||
func expectFailureCount(tableName string, projectionName, instanceID string, failedSeq, failureCount uint64) func(sqlmock.Sqlmock) {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectQuery(`WITH failures AS \(SELECT failure_count FROM `+tableName+` WHERE projection_name = \$1 AND failed_sequence = \$2\ AND instance_id = \$3\) SELECT IF\(EXISTS\(SELECT failure_count FROM failures\), \(SELECT failure_count FROM failures\), 0\) AS failure_count`).
|
||||
m.ExpectQuery(`WITH failures AS \(SELECT failure_count FROM `+tableName+` WHERE projection_name = \$1 AND failed_sequence = \$2 AND instance_id = \$3\) SELECT COALESCE\(\(SELECT failure_count FROM failures\), 0\) AS failure_count`).
|
||||
WithArgs(projectionName, failedSeq, instanceID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"failure_count"}).
|
||||
@ -28,7 +28,7 @@ func expectFailureCount(tableName string, projectionName, instanceID string, fai
|
||||
|
||||
func expectUpdateFailureCount(tableName string, projectionName, instanceID string, seq, failureCount uint64) func(sqlmock.Sqlmock) {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectExec(`UPSERT INTO `+tableName+` \(projection_name, failed_sequence, failure_count, error, instance_id\) VALUES \(\$1, \$2, \$3, \$4\, \$5\)`).
|
||||
m.ExpectExec(`INSERT INTO `+tableName+` \(projection_name, failed_sequence, failure_count, error, instance_id\) VALUES \(\$1, \$2, \$3, \$4\, \$5\) ON CONFLICT \(projection_name, failed_sequence, instance_id\) DO UPDATE SET failure_count = EXCLUDED\.failure_count, error = EXCLUDED\.error`).
|
||||
WithArgs(projectionName, seq, failureCount, sqlmock.AnyArg(), instanceID).WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
}
|
||||
}
|
||||
@ -133,7 +133,7 @@ func expectCurrentSequence(tableName, projection string, seq uint64, aggregateTy
|
||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM `+tableName+` WHERE projection_name = \$1 AND instance_id = ANY \(\$2\) FOR UPDATE`).
|
||||
WithArgs(
|
||||
projection,
|
||||
pq.StringArray(instanceIDs),
|
||||
database.StringArray(instanceIDs),
|
||||
).
|
||||
WillReturnRows(
|
||||
rows,
|
||||
@ -146,7 +146,7 @@ func expectCurrentSequenceErr(tableName, projection string, instanceIDs []string
|
||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM `+tableName+` WHERE projection_name = \$1 AND instance_id = ANY \(\$2\) FOR UPDATE`).
|
||||
WithArgs(
|
||||
projection,
|
||||
pq.StringArray(instanceIDs),
|
||||
database.StringArray(instanceIDs),
|
||||
).
|
||||
WillReturnError(err)
|
||||
}
|
||||
@ -157,7 +157,7 @@ func expectCurrentSequenceNoRows(tableName, projection string, instanceIDs []str
|
||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM `+tableName+` WHERE projection_name = \$1 AND instance_id = ANY \(\$2\) FOR UPDATE`).
|
||||
WithArgs(
|
||||
projection,
|
||||
pq.StringArray(instanceIDs),
|
||||
database.StringArray(instanceIDs),
|
||||
).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"current_sequence", "aggregate_type", "instance_id"}),
|
||||
@ -170,7 +170,7 @@ func expectCurrentSequenceScanErr(tableName, projection string, instanceIDs []st
|
||||
m.ExpectQuery(`SELECT current_sequence, aggregate_type, instance_id FROM `+tableName+` WHERE projection_name = \$1 AND instance_id = ANY \(\$2\) FOR UPDATE`).
|
||||
WithArgs(
|
||||
projection,
|
||||
pq.StringArray(instanceIDs),
|
||||
database.StringArray(instanceIDs),
|
||||
).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"current_sequence", "aggregate_type", "instance_id"}).
|
||||
@ -182,7 +182,7 @@ func expectCurrentSequenceScanErr(tableName, projection string, instanceIDs []st
|
||||
|
||||
func expectUpdateCurrentSequence(tableName, projection string, seq uint64, aggregateType, instanceID string) func(sqlmock.Sqlmock) {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\)`).
|
||||
m.ExpectExec("INSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\) ON CONFLICT \(projection_name, aggregate_type, instance_id\) DO UPDATE SET current_sequence = EXCLUDED.current_sequence, timestamp = EXCLUDED.timestamp`).
|
||||
WithArgs(
|
||||
projection,
|
||||
aggregateType,
|
||||
@ -213,7 +213,7 @@ func expectUpdateThreeCurrentSequence(t *testing.T, tableName, projection string
|
||||
matchers[i] = matcher
|
||||
}
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectExec("UPSERT INTO " + tableName + ` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\), \(\$5, \$6, \$7, \$8, NOW\(\)\), \(\$9, \$10, \$11, \$12, NOW\(\)\)`).
|
||||
m.ExpectExec("INSERT INTO " + tableName + ` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\), \(\$5, \$6, \$7, \$8, NOW\(\)\), \(\$9, \$10, \$11, \$12, NOW\(\)\) ON CONFLICT \(projection_name, aggregate_type, instance_id\) DO UPDATE SET current_sequence = EXCLUDED.current_sequence, timestamp = EXCLUDED.timestamp`).
|
||||
WithArgs(
|
||||
matchers...,
|
||||
).
|
||||
@ -262,7 +262,7 @@ func (m *currentSequenceMatcher) Match(value driver.Value) bool {
|
||||
|
||||
func expectUpdateCurrentSequenceErr(tableName, projection string, seq uint64, err error, aggregateType, instanceID string) func(sqlmock.Sqlmock) {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\)`).
|
||||
m.ExpectExec("INSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\) ON CONFLICT \(projection_name, aggregate_type, instance_id\) DO UPDATE SET current_sequence = EXCLUDED.current_sequence, timestamp = EXCLUDED.timestamp`).
|
||||
WithArgs(
|
||||
projection,
|
||||
aggregateType,
|
||||
@ -275,7 +275,7 @@ func expectUpdateCurrentSequenceErr(tableName, projection string, seq uint64, er
|
||||
|
||||
func expectUpdateCurrentSequenceNoRows(tableName, projection string, seq uint64, aggregateType, instanceID string) func(sqlmock.Sqlmock) {
|
||||
return func(m sqlmock.Sqlmock) {
|
||||
m.ExpectExec("UPSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\)`).
|
||||
m.ExpectExec("INSERT INTO "+tableName+` \(projection_name, aggregate_type, current_sequence, instance_id, timestamp\) VALUES \(\$1, \$2, \$3, \$4, NOW\(\)\) ON CONFLICT \(projection_name, aggregate_type, instance_id\) DO UPDATE SET current_sequence = EXCLUDED.current_sequence, timestamp = EXCLUDED.timestamp`).
|
||||
WithArgs(
|
||||
projection,
|
||||
aggregateType,
|
||||
@ -297,10 +297,10 @@ func expectLock(lockTable, workerName string, d time.Duration, instanceID string
|
||||
` WHERE `+lockTable+`\.projection_name = \$3 AND `+lockTable+`\.instance_id = ANY \(\$5\) AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
||||
WithArgs(
|
||||
workerName,
|
||||
float64(d),
|
||||
d,
|
||||
projectionName,
|
||||
instanceID,
|
||||
pq.StringArray{instanceID},
|
||||
database.StringArray{instanceID},
|
||||
).
|
||||
WillReturnResult(
|
||||
sqlmock.NewResult(1, 1),
|
||||
@ -317,11 +317,11 @@ func expectLockMultipleInstances(lockTable, workerName string, d time.Duration,
|
||||
` WHERE `+lockTable+`\.projection_name = \$3 AND `+lockTable+`\.instance_id = ANY \(\$6\) AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
||||
WithArgs(
|
||||
workerName,
|
||||
float64(d),
|
||||
d,
|
||||
projectionName,
|
||||
instanceID1,
|
||||
instanceID2,
|
||||
pq.StringArray{instanceID1, instanceID2},
|
||||
database.StringArray{instanceID1, instanceID2},
|
||||
).
|
||||
WillReturnResult(
|
||||
sqlmock.NewResult(1, 1),
|
||||
@ -338,10 +338,10 @@ func expectLockNoRows(lockTable, workerName string, d time.Duration, instanceID
|
||||
` WHERE `+lockTable+`\.projection_name = \$3 AND `+lockTable+`\.instance_id = ANY \(\$5\) AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
||||
WithArgs(
|
||||
workerName,
|
||||
float64(d),
|
||||
d,
|
||||
projectionName,
|
||||
instanceID,
|
||||
pq.StringArray{instanceID},
|
||||
database.StringArray{instanceID},
|
||||
).
|
||||
WillReturnResult(driver.ResultNoRows)
|
||||
}
|
||||
@ -356,10 +356,10 @@ func expectLockErr(lockTable, workerName string, d time.Duration, instanceID str
|
||||
` WHERE `+lockTable+`\.projection_name = \$3 AND `+lockTable+`\.instance_id = ANY \(\$5\) AND \(`+lockTable+`\.locker_id = \$1 OR `+lockTable+`\.locked_until < now\(\)\)`).
|
||||
WithArgs(
|
||||
workerName,
|
||||
float64(d),
|
||||
d,
|
||||
projectionName,
|
||||
instanceID,
|
||||
pq.StringArray{instanceID},
|
||||
database.StringArray{instanceID},
|
||||
).
|
||||
WillReturnError(err)
|
||||
}
|
||||
|
@ -10,15 +10,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
setFailureCountStmtFormat = "UPSERT INTO %s" +
|
||||
setFailureCountStmtFormat = "INSERT INTO %s" +
|
||||
" (projection_name, failed_sequence, failure_count, error, instance_id)" +
|
||||
" VALUES ($1, $2, $3, $4, $5)"
|
||||
" VALUES ($1, $2, $3, $4, $5) ON CONFLICT (projection_name, failed_sequence, instance_id)" +
|
||||
" DO UPDATE SET failure_count = EXCLUDED.failure_count, error = EXCLUDED.error"
|
||||
failureCountStmtFormat = "WITH failures AS (SELECT failure_count FROM %s WHERE projection_name = $1 AND failed_sequence = $2 AND instance_id = $3)" +
|
||||
" SELECT IF(" +
|
||||
"EXISTS(SELECT failure_count FROM failures)," +
|
||||
" (SELECT failure_count FROM failures)," +
|
||||
" 0" +
|
||||
") AS failure_count"
|
||||
" SELECT COALESCE((SELECT failure_count FROM failures), 0) AS failure_count"
|
||||
)
|
||||
|
||||
func (h *StatementHandler) handleFailedStmt(tx *sql.Tx, stmt *handler.Statement, execErr error) (shouldContinue bool) {
|
||||
|
@ -72,12 +72,12 @@ func NewStatementHandler(
|
||||
aggregates: aggregateTypes,
|
||||
reduces: reduces,
|
||||
bulkLimit: config.BulkLimit,
|
||||
Locker: NewLocker(config.Client, config.LockTable, config.ProjectionHandlerConfig.ProjectionName),
|
||||
Locker: NewLocker(config.Client, config.LockTable, config.ProjectionName),
|
||||
}
|
||||
h.ProjectionHandler = handler.NewProjectionHandler(ctx, config.ProjectionHandlerConfig, h.reduce, h.Update, h.SearchQuery, h.Lock, h.Unlock)
|
||||
|
||||
err := h.Init(ctx, config.InitCheck)
|
||||
logging.OnError(err).Fatal("unable to initialize projections")
|
||||
logging.OnError(err).WithField("projection", config.ProjectionName).Fatal("unable to initialize projections")
|
||||
|
||||
h.Subscribe(h.aggregates...)
|
||||
|
||||
|
@ -6,11 +6,10 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/jackc/pgconn"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||
)
|
||||
|
||||
@ -280,7 +279,7 @@ func isErrAlreadyExists(err error) bool {
|
||||
if !errors.As(err, &caosErr) {
|
||||
return false
|
||||
}
|
||||
sqlErr, ok := caosErr.GetParent().(*pq.Error)
|
||||
sqlErr, ok := caosErr.GetParent().(*pgconn.PgError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
@ -288,14 +287,11 @@ func isErrAlreadyExists(err error) bool {
|
||||
}
|
||||
|
||||
func createTableStatement(table *Table, tableName string, suffix string) string {
|
||||
stmt := fmt.Sprintf("CREATE TABLE %s (%s, PRIMARY KEY (%s)",
|
||||
stmt := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (%s, PRIMARY KEY (%s)",
|
||||
tableName+suffix,
|
||||
createColumnsStatement(table.columns, tableName),
|
||||
strings.Join(table.primaryKey, ", "),
|
||||
)
|
||||
for _, index := range table.indices {
|
||||
stmt += fmt.Sprintf(", INDEX %s (%s)", index.Name, strings.Join(index.Columns, ","))
|
||||
}
|
||||
for _, key := range table.foreignKeys {
|
||||
ref := tableName
|
||||
if len(key.RefColumns) > 0 {
|
||||
@ -309,7 +305,13 @@ func createTableStatement(table *Table, tableName string, suffix string) string
|
||||
for _, constraint := range table.constraints {
|
||||
stmt += fmt.Sprintf(", CONSTRAINT %s UNIQUE (%s)", constraint.Name, strings.Join(constraint.Columns, ","))
|
||||
}
|
||||
return stmt + ");"
|
||||
|
||||
stmt += ");"
|
||||
|
||||
for _, index := range table.indices {
|
||||
stmt += fmt.Sprintf("CREATE INDEX IF NOT EXISTS %s ON %s (%s);", index.Name, tableName+suffix, strings.Join(index.Columns, ","))
|
||||
}
|
||||
return stmt
|
||||
}
|
||||
|
||||
func createViewStatement(viewName string, selectStmt string) string {
|
||||
@ -321,7 +323,7 @@ func createViewStatement(viewName string, selectStmt string) string {
|
||||
|
||||
func createIndexStatement(index *Index) func(config execConfig) string {
|
||||
return func(config execConfig) string {
|
||||
stmt := fmt.Sprintf("CREATE INDEX %s ON %s (%s)",
|
||||
stmt := fmt.Sprintf("CREATE INDEX IF NOT EXISTS %s ON %s (%s)",
|
||||
index.Name,
|
||||
config.tableName,
|
||||
strings.Join(index.Columns, ","),
|
||||
@ -380,9 +382,8 @@ func columnType(columnType ColumnType) string {
|
||||
case ColumnTypeJSONB:
|
||||
return "JSONB"
|
||||
case ColumnTypeBytes:
|
||||
return "BYTES"
|
||||
return "BYTEA"
|
||||
default:
|
||||
panic("unknown column type")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
)
|
||||
@ -91,17 +91,17 @@ func (h *locker) Unlock(instanceIDs ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *locker) lockStatement(lockDuration time.Duration, instanceIDs []string) (string, []interface{}) {
|
||||
func (h *locker) lockStatement(lockDuration time.Duration, instanceIDs database.StringArray) (string, []interface{}) {
|
||||
valueQueries := make([]string, len(instanceIDs))
|
||||
values := make([]interface{}, len(instanceIDs)+4)
|
||||
values[0] = h.workerName
|
||||
//the unit of crdb interval is seconds (https://www.cockroachlabs.com/docs/stable/interval.html).
|
||||
values[1] = lockDuration.Seconds()
|
||||
values[1] = lockDuration
|
||||
values[2] = h.projectionName
|
||||
for i, instanceID := range instanceIDs {
|
||||
valueQueries[i] = "($1, now()+$2::INTERVAL, $3, $" + strconv.Itoa(i+4) + ")"
|
||||
values[i+3] = instanceID
|
||||
}
|
||||
values[len(values)-1] = pq.StringArray(instanceIDs)
|
||||
values[len(values)-1] = instanceIDs
|
||||
return h.lockStmt(strings.Join(valueQueries, ", "), len(values)), values
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
z_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
)
|
||||
|
||||
@ -43,9 +44,9 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
||||
name: "lock fails",
|
||||
want: want{
|
||||
expectations: []mockExpectation{
|
||||
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||
expectLockErr(lockTable, workerName, 2, "instanceID", errLock),
|
||||
expectLock(lockTable, workerName, 2*time.Second, "instanceID"),
|
||||
expectLock(lockTable, workerName, 2*time.Second, "instanceID"),
|
||||
expectLockErr(lockTable, workerName, 2*time.Second, "instanceID", errLock),
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
@ -63,8 +64,8 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
||||
name: "success",
|
||||
want: want{
|
||||
expectations: []mockExpectation{
|
||||
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||
expectLock(lockTable, workerName, 2, "instanceID"),
|
||||
expectLock(lockTable, workerName, 2*time.Second, "instanceID"),
|
||||
expectLock(lockTable, workerName, 2*time.Second, "instanceID"),
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
@ -81,8 +82,8 @@ func TestStatementHandler_handleLock(t *testing.T) {
|
||||
name: "success with multiple",
|
||||
want: want{
|
||||
expectations: []mockExpectation{
|
||||
expectLockMultipleInstances(lockTable, workerName, 2, "instanceID1", "instanceID2"),
|
||||
expectLockMultipleInstances(lockTable, workerName, 2, "instanceID1", "instanceID2"),
|
||||
expectLockMultipleInstances(lockTable, workerName, 2*time.Second, "instanceID1", "instanceID2"),
|
||||
expectLockMultipleInstances(lockTable, workerName, 2*time.Second, "instanceID1", "instanceID2"),
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
@ -149,7 +150,7 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
||||
name: "lock fails",
|
||||
want: want{
|
||||
expectations: []mockExpectation{
|
||||
expectLockErr(lockTable, workerName, 1, "instanceID", sql.ErrTxDone),
|
||||
expectLockErr(lockTable, workerName, 1*time.Second, "instanceID", sql.ErrTxDone),
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return errors.Is(err, sql.ErrTxDone)
|
||||
@ -157,14 +158,14 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
||||
},
|
||||
args: args{
|
||||
lockDuration: 1 * time.Second,
|
||||
instanceIDs: []string{"instanceID"},
|
||||
instanceIDs: database.StringArray{"instanceID"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "lock no rows",
|
||||
want: want{
|
||||
expectations: []mockExpectation{
|
||||
expectLockNoRows(lockTable, workerName, 2, "instanceID"),
|
||||
expectLockNoRows(lockTable, workerName, 2*time.Second, "instanceID"),
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return errors.Is(err, renewNoRowsAffectedErr)
|
||||
@ -172,14 +173,14 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
||||
},
|
||||
args: args{
|
||||
lockDuration: 2 * time.Second,
|
||||
instanceIDs: []string{"instanceID"},
|
||||
instanceIDs: database.StringArray{"instanceID"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
want: want{
|
||||
expectations: []mockExpectation{
|
||||
expectLock(lockTable, workerName, 3, "instanceID"),
|
||||
expectLock(lockTable, workerName, 3*time.Second, "instanceID"),
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return errors.Is(err, nil)
|
||||
@ -187,14 +188,14 @@ func TestStatementHandler_renewLock(t *testing.T) {
|
||||
},
|
||||
args: args{
|
||||
lockDuration: 3 * time.Second,
|
||||
instanceIDs: []string{"instanceID"},
|
||||
instanceIDs: database.StringArray{"instanceID"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "success with multiple",
|
||||
want: want{
|
||||
expectations: []mockExpectation{
|
||||
expectLockMultipleInstances(lockTable, workerName, 3, "instanceID1", "instanceID2"),
|
||||
expectLockMultipleInstances(lockTable, workerName, 3*time.Second, "instanceID1", "instanceID2"),
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return errors.Is(err, nil)
|
||||
|
@ -4,8 +4,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
"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"
|
||||
@ -51,10 +50,13 @@ func NewCreateStatement(event eventstore.Event, values []handler.Column, opts ..
|
||||
}
|
||||
}
|
||||
|
||||
func NewUpsertStatement(event eventstore.Event, values []handler.Column, opts ...execOption) *handler.Statement {
|
||||
func NewUpsertStatement(event eventstore.Event, conflictCols []handler.Column, values []handler.Column, opts ...execOption) *handler.Statement {
|
||||
cols, params, args := columnsToQuery(values)
|
||||
columnNames := strings.Join(cols, ", ")
|
||||
valuesPlaceholder := strings.Join(params, ", ")
|
||||
|
||||
conflictTarget := make([]string, len(conflictCols))
|
||||
for i, col := range conflictCols {
|
||||
conflictTarget[i] = col.Name
|
||||
}
|
||||
|
||||
config := execConfig{
|
||||
args: args,
|
||||
@ -64,8 +66,14 @@ func NewUpsertStatement(event eventstore.Event, values []handler.Column, opts ..
|
||||
config.err = handler.ErrNoValues
|
||||
}
|
||||
|
||||
updateCols, updateVals := getUpdateCols(cols, conflictTarget)
|
||||
if len(updateCols) == 0 || len(updateVals) == 0 {
|
||||
config.err = handler.ErrNoValues
|
||||
}
|
||||
|
||||
q := func(config execConfig) string {
|
||||
return "UPSERT INTO " + config.tableName + " (" + columnNames + ") VALUES (" + valuesPlaceholder + ")"
|
||||
return "INSERT INTO " + config.tableName + " (" + strings.Join(cols, ", ") + ") VALUES (" + strings.Join(params, ", ") + ")" +
|
||||
" ON CONFLICT (" + strings.Join(conflictTarget, ", ") + ") DO UPDATE SET (" + strings.Join(updateCols, ", ") + ") = (" + strings.Join(updateVals, ", ") + ")"
|
||||
}
|
||||
|
||||
return &handler.Statement{
|
||||
@ -77,15 +85,38 @@ func NewUpsertStatement(event eventstore.Event, values []handler.Column, opts ..
|
||||
}
|
||||
}
|
||||
|
||||
func getUpdateCols(cols, conflictTarget []string) (updateCols, updateVals []string) {
|
||||
updateCols = make([]string, len(cols))
|
||||
updateVals = make([]string, len(cols))
|
||||
|
||||
copy(updateCols, cols)
|
||||
|
||||
for i := len(updateCols) - 1; i >= 0; i-- {
|
||||
updateVals[i] = "EXCLUDED." + updateCols[i]
|
||||
|
||||
for _, conflict := range conflictTarget {
|
||||
if conflict == updateCols[i] {
|
||||
copy(updateCols[i:], updateCols[i+1:])
|
||||
updateCols[len(updateCols)-1] = ""
|
||||
updateCols = updateCols[:len(updateCols)-1]
|
||||
|
||||
copy(updateVals[i:], updateVals[i+1:])
|
||||
updateVals[len(updateVals)-1] = ""
|
||||
updateVals = updateVals[:len(updateVals)-1]
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return updateCols, updateVals
|
||||
}
|
||||
|
||||
func NewUpdateStatement(event eventstore.Event, values []handler.Column, conditions []handler.Condition, opts ...execOption) *handler.Statement {
|
||||
cols, params, args := columnsToQuery(values)
|
||||
wheres, whereArgs := conditionsToWhere(conditions, len(params))
|
||||
args = append(args, whereArgs...)
|
||||
|
||||
columnNames := strings.Join(cols, ", ")
|
||||
valuesPlaceholder := strings.Join(params, ", ")
|
||||
wheresPlaceholders := strings.Join(wheres, " AND ")
|
||||
|
||||
config := execConfig{
|
||||
args: args,
|
||||
}
|
||||
@ -99,7 +130,7 @@ func NewUpdateStatement(event eventstore.Event, values []handler.Column, conditi
|
||||
}
|
||||
|
||||
q := func(config execConfig) string {
|
||||
return "UPDATE " + config.tableName + " SET (" + columnNames + ") = (" + valuesPlaceholder + ") WHERE " + wheresPlaceholders
|
||||
return "UPDATE " + config.tableName + " SET (" + strings.Join(cols, ", ") + ") = (" + strings.Join(params, ", ") + ") WHERE " + strings.Join(wheres, " AND ")
|
||||
}
|
||||
|
||||
return &handler.Statement{
|
||||
@ -171,9 +202,9 @@ func AddCreateStatement(columns []handler.Column, opts ...execOption) func(event
|
||||
}
|
||||
}
|
||||
|
||||
func AddUpsertStatement(values []handler.Column, opts ...execOption) func(eventstore.Event) Exec {
|
||||
func AddUpsertStatement(indexCols []handler.Column, values []handler.Column, opts ...execOption) func(eventstore.Event) Exec {
|
||||
return func(event eventstore.Event) Exec {
|
||||
return NewUpsertStatement(event, values, opts...).Execute
|
||||
return NewUpsertStatement(event, indexCols, values, opts...).Execute
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,9 +220,9 @@ func AddDeleteStatement(conditions []handler.Condition, opts ...execOption) func
|
||||
}
|
||||
}
|
||||
|
||||
func AddCopyStatement(from, to []handler.Column, conditions []handler.Condition, opts ...execOption) func(eventstore.Event) Exec {
|
||||
func AddCopyStatement(conflict, from, to []handler.Column, conditions []handler.Condition, opts ...execOption) func(eventstore.Event) Exec {
|
||||
return func(event eventstore.Event) Exec {
|
||||
return NewCopyStatement(event, from, to, conditions, opts...).Execute
|
||||
return NewCopyStatement(event, conflict, from, to, conditions, opts...).Execute
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,11 +249,9 @@ func NewArrayRemoveCol(column string, value interface{}) handler.Column {
|
||||
func NewArrayIntersectCol(column string, value interface{}) handler.Column {
|
||||
var arrayType string
|
||||
switch value.(type) {
|
||||
case pq.StringArray:
|
||||
arrayType = "STRING"
|
||||
case pq.Int32Array,
|
||||
pq.Int64Array:
|
||||
arrayType = "INT"
|
||||
|
||||
case []string, database.StringArray:
|
||||
arrayType = "TEXT"
|
||||
//TODO: handle more types if necessary
|
||||
}
|
||||
return handler.Column{
|
||||
@ -239,20 +268,24 @@ func NewArrayIntersectCol(column string, value interface{}) handler.Column {
|
||||
// if the value of a col is empty the data will be copied from the selected row
|
||||
// if the value of a col is not empty the data will be set by the static value
|
||||
// conds represent the conditions for the selection subquery
|
||||
func NewCopyStatement(event eventstore.Event, from, to []handler.Column, conds []handler.Condition, opts ...execOption) *handler.Statement {
|
||||
func NewCopyStatement(event eventstore.Event, conflictCols, from, to []handler.Column, conds []handler.Condition, opts ...execOption) *handler.Statement {
|
||||
columnNames := make([]string, len(to))
|
||||
selectColumns := make([]string, len(from))
|
||||
updateColumns := make([]string, len(columnNames))
|
||||
argCounter := 0
|
||||
args := []interface{}{}
|
||||
|
||||
for i := range from {
|
||||
for i, col := range from {
|
||||
columnNames[i] = to[i].Name
|
||||
selectColumns[i] = from[i].Name
|
||||
if from[i].Value != nil {
|
||||
updateColumns[i] = "EXCLUDED." + col.Name
|
||||
if col.Value != nil {
|
||||
argCounter++
|
||||
selectColumns[i] = "$" + strconv.Itoa(argCounter)
|
||||
args = append(args, from[i].Value)
|
||||
updateColumns[i] = selectColumns[i]
|
||||
args = append(args, col.Value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wheres := make([]string, len(conds))
|
||||
@ -262,6 +295,11 @@ func NewCopyStatement(event eventstore.Event, from, to []handler.Column, conds [
|
||||
args = append(args, cond.Value)
|
||||
}
|
||||
|
||||
conflictTargets := make([]string, len(conflictCols))
|
||||
for i, conflictCol := range conflictCols {
|
||||
conflictTargets[i] = conflictCol.Name
|
||||
}
|
||||
|
||||
config := execConfig{
|
||||
args: args,
|
||||
}
|
||||
@ -275,7 +313,7 @@ func NewCopyStatement(event eventstore.Event, from, to []handler.Column, conds [
|
||||
}
|
||||
|
||||
q := func(config execConfig) string {
|
||||
return "UPSERT INTO " +
|
||||
return "INSERT INTO " +
|
||||
config.tableName +
|
||||
" (" +
|
||||
strings.Join(columnNames, ", ") +
|
||||
@ -283,7 +321,14 @@ func NewCopyStatement(event eventstore.Event, from, to []handler.Column, conds [
|
||||
strings.Join(selectColumns, ", ") +
|
||||
" FROM " +
|
||||
config.tableName + " AS copy_table WHERE " +
|
||||
strings.Join(wheres, " AND ")
|
||||
strings.Join(wheres, " AND ") +
|
||||
" ON CONFLICT (" +
|
||||
strings.Join(conflictTargets, ", ") +
|
||||
") DO UPDATE SET (" +
|
||||
strings.Join(columnNames, ", ") +
|
||||
") = (" +
|
||||
strings.Join(updateColumns, ", ") +
|
||||
")"
|
||||
}
|
||||
|
||||
return &handler.Statement{
|
||||
|
@ -180,6 +180,7 @@ func TestNewUpsertStatement(t *testing.T) {
|
||||
type args struct {
|
||||
table string
|
||||
event *testEvent
|
||||
conflictCols []handler.Column
|
||||
values []handler.Column
|
||||
}
|
||||
type want struct {
|
||||
@ -249,7 +250,7 @@ func TestNewUpsertStatement(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "correct",
|
||||
name: "no update cols",
|
||||
args: args{
|
||||
table: "my_table",
|
||||
event: &testEvent{
|
||||
@ -257,6 +258,9 @@ func TestNewUpsertStatement(t *testing.T) {
|
||||
sequence: 1,
|
||||
previousSequence: 0,
|
||||
},
|
||||
conflictCols: []handler.Column{
|
||||
handler.NewCol("col1", nil),
|
||||
},
|
||||
values: []handler.Column{
|
||||
{
|
||||
Name: "col1",
|
||||
@ -264,6 +268,42 @@ func TestNewUpsertStatement(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
table: "my_table",
|
||||
aggregateType: "agg",
|
||||
sequence: 1,
|
||||
previousSequence: 1,
|
||||
executer: &wantExecuter{
|
||||
shouldExecute: false,
|
||||
},
|
||||
isErr: func(err error) bool {
|
||||
return errors.Is(err, handler.ErrNoValues)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "correct",
|
||||
args: args{
|
||||
table: "my_table",
|
||||
event: &testEvent{
|
||||
aggregateType: "agg",
|
||||
sequence: 1,
|
||||
previousSequence: 0,
|
||||
},
|
||||
conflictCols: []handler.Column{
|
||||
handler.NewCol("col1", nil),
|
||||
},
|
||||
values: []handler.Column{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: "val",
|
||||
},
|
||||
{
|
||||
Name: "col2",
|
||||
Value: "val",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
table: "my_table",
|
||||
aggregateType: "agg",
|
||||
@ -272,8 +312,8 @@ func TestNewUpsertStatement(t *testing.T) {
|
||||
executer: &wantExecuter{
|
||||
params: []params{
|
||||
{
|
||||
query: "UPSERT INTO my_table (col1) VALUES ($1)",
|
||||
args: []interface{}{"val"},
|
||||
query: "INSERT INTO my_table (col1, col2) VALUES ($1, $2) ON CONFLICT (col1) DO UPDATE SET (col2) = (EXCLUDED.col2)",
|
||||
args: []interface{}{"val", "val"},
|
||||
},
|
||||
},
|
||||
shouldExecute: true,
|
||||
@ -287,7 +327,7 @@ func TestNewUpsertStatement(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.want.executer.t = t
|
||||
stmt := NewUpsertStatement(tt.args.event, tt.args.values)
|
||||
stmt := NewUpsertStatement(tt.args.event, tt.args.conflictCols, tt.args.values)
|
||||
|
||||
err := stmt.Execute(tt.want.executer, tt.args.table)
|
||||
if !tt.want.isErr(err) {
|
||||
@ -724,11 +764,18 @@ func TestNewMultiStatement(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
AddUpsertStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol("col1", nil),
|
||||
},
|
||||
[]handler.Column{
|
||||
{
|
||||
Name: "col1",
|
||||
Value: 1,
|
||||
},
|
||||
{
|
||||
Name: "col2",
|
||||
Value: 2,
|
||||
},
|
||||
}),
|
||||
AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
@ -761,8 +808,8 @@ func TestNewMultiStatement(t *testing.T) {
|
||||
args: []interface{}{1},
|
||||
},
|
||||
{
|
||||
query: "UPSERT INTO my_table (col1) VALUES ($1)",
|
||||
args: []interface{}{1},
|
||||
query: "INSERT INTO my_table (col1, col2) VALUES ($1, $2) ON CONFLICT (col1) DO UPDATE SET (col2) = (EXCLUDED.col2)",
|
||||
args: []interface{}{1, 2},
|
||||
},
|
||||
{
|
||||
query: "UPDATE my_table SET (col1) = ($1) WHERE (col1 = $2)",
|
||||
@ -801,6 +848,7 @@ func TestNewCopyStatement(t *testing.T) {
|
||||
type args struct {
|
||||
table string
|
||||
event *testEvent
|
||||
conflictingCols []handler.Column
|
||||
from []handler.Column
|
||||
to []handler.Column
|
||||
conds []handler.Condition
|
||||
@ -1004,7 +1052,7 @@ func TestNewCopyStatement(t *testing.T) {
|
||||
executer: &wantExecuter{
|
||||
params: []params{
|
||||
{
|
||||
query: "UPSERT INTO my_table (state, id, col_a, col_b) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE copy_table.id = $2 AND copy_table.state = $3",
|
||||
query: "INSERT INTO my_table (state, id, col_a, col_b) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE copy_table.id = $2 AND copy_table.state = $3 ON CONFLICT () DO UPDATE SET (state, id, col_a, col_b) = ($1, EXCLUDED.id, EXCLUDED.col_a, EXCLUDED.col_b)",
|
||||
args: []interface{}{1, 2, 3},
|
||||
},
|
||||
},
|
||||
@ -1071,7 +1119,7 @@ func TestNewCopyStatement(t *testing.T) {
|
||||
executer: &wantExecuter{
|
||||
params: []params{
|
||||
{
|
||||
query: "UPSERT INTO my_table (state, id, col_c, col_d) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE copy_table.id = $2 AND copy_table.state = $3",
|
||||
query: "INSERT INTO my_table (state, id, col_c, col_d) SELECT $1, id, col_a, col_b FROM my_table AS copy_table WHERE copy_table.id = $2 AND copy_table.state = $3 ON CONFLICT () DO UPDATE SET (state, id, col_c, col_d) = ($1, EXCLUDED.id, EXCLUDED.col_a, EXCLUDED.col_b)",
|
||||
args: []interface{}{1, 2, 3},
|
||||
},
|
||||
},
|
||||
@ -1086,7 +1134,7 @@ func TestNewCopyStatement(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.want.executer.t = t
|
||||
stmt := NewCopyStatement(tt.args.event, tt.args.from, tt.args.to, tt.args.conds)
|
||||
stmt := NewCopyStatement(tt.args.event, tt.args.conflictingCols, tt.args.from, tt.args.to, tt.args.conds)
|
||||
|
||||
err := stmt.Execute(tt.want.executer, tt.args.table)
|
||||
if !tt.want.isErr(err) {
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/cmd/initialise"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/database/cockroach"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -45,13 +47,20 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func initDB(db *sql.DB) error {
|
||||
username := "zitadel"
|
||||
database := "zitadel"
|
||||
err := initialise.Initialise(db, initialise.VerifyUser(username, ""),
|
||||
initialise.VerifyDatabase(database),
|
||||
initialise.VerifyGrant(database, username))
|
||||
initialise.ReadStmts("cockroach")
|
||||
config := new(database.Config)
|
||||
config.SetConnector(&cockroach.Config{
|
||||
User: cockroach.User{
|
||||
Username: "zitadel",
|
||||
},
|
||||
Database: "zitadel",
|
||||
})
|
||||
err := initialise.Init(db,
|
||||
initialise.VerifyUser(config.Username(), ""),
|
||||
initialise.VerifyDatabase(config.Database()),
|
||||
initialise.VerifyGrant(config.Database(), config.Username()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return initialise.VerifyZitadel(db)
|
||||
return initialise.VerifyZitadel(db, *config)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/cockroach-go/v2/crdb"
|
||||
"github.com/jackc/pgconn"
|
||||
"github.com/lib/pq"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
@ -30,7 +31,7 @@ const (
|
||||
" SELECT MAX(event_sequence) seq, 1 join_me" +
|
||||
" FROM eventstore.events" +
|
||||
" WHERE aggregate_type = $2" +
|
||||
" AND (CASE WHEN $9::STRING IS NULL THEN instance_id is null else instance_id = $9::STRING END)" +
|
||||
" AND (CASE WHEN $9::TEXT IS NULL THEN instance_id is null else instance_id = $9::TEXT END)" +
|
||||
") AS agg_type " +
|
||||
// combined with
|
||||
"LEFT JOIN " +
|
||||
@ -39,7 +40,7 @@ const (
|
||||
" SELECT event_sequence seq, resource_owner ro, 1 join_me" +
|
||||
" FROM eventstore.events" +
|
||||
" WHERE aggregate_type = $2 AND aggregate_id = $3" +
|
||||
" AND (CASE WHEN $9::STRING IS NULL THEN instance_id is null else instance_id = $9::STRING END)" +
|
||||
" AND (CASE WHEN $9::TEXT IS NULL THEN instance_id is null else instance_id = $9::TEXT END)" +
|
||||
" ORDER BY event_sequence DESC" +
|
||||
" LIMIT 1" +
|
||||
") AS agg USING(join_me)" +
|
||||
@ -69,9 +70,9 @@ const (
|
||||
" $5::JSONB AS event_data," +
|
||||
" $6::VARCHAR AS editor_user," +
|
||||
" $7::VARCHAR AS editor_service," +
|
||||
" IFNULL((resource_owner), $8::VARCHAR) AS resource_owner," +
|
||||
" COALESCE((resource_owner), $8::VARCHAR) AS resource_owner," +
|
||||
" $9::VARCHAR AS instance_id," +
|
||||
" NEXTVAL(CONCAT('eventstore.', IF($9 <> '', CONCAT('i_', $9), 'system'), '_seq'))," +
|
||||
" NEXTVAL(CONCAT('eventstore.', (CASE WHEN $9 <> '' THEN CONCAT('i_', $9) ELSE 'system' END), '_seq'))," +
|
||||
" aggregate_sequence AS previous_aggregate_sequence," +
|
||||
" aggregate_type_sequence AS previous_aggregate_type_sequence " +
|
||||
"FROM previous_data " +
|
||||
@ -156,7 +157,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, '_seq')", instanceID)
|
||||
row := db.client.QueryRowContext(ctx, "SELECT CONCAT('eventstore.i_', $1::TEXT, '_seq')", instanceID)
|
||||
if row.Err() != nil {
|
||||
return caos_errs.ThrowInvalidArgument(row.Err(), "SQL-7gtFA", "Errors.InvalidArgument")
|
||||
}
|
||||
@ -355,5 +356,10 @@ func (db *CRDB) isUniqueViolationError(err error) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if pgxErr, ok := err.(*pgconn.PgError); ok {
|
||||
if pgxErr.Code == "23505" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -6,8 +6,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
|
||||
@ -279,7 +278,7 @@ func TestCRDB_Push_OneAggregate(t *testing.T) {
|
||||
uniqueCount int
|
||||
assetCount int
|
||||
aggType repository.AggregateType
|
||||
aggID []string
|
||||
aggID database.StringArray
|
||||
}
|
||||
type res struct {
|
||||
wantErr bool
|
||||
@ -430,7 +429,7 @@ func TestCRDB_Push_OneAggregate(t *testing.T) {
|
||||
t.Errorf("CRDB.Push() error = %v, wantErr %v", err, tt.res.wantErr)
|
||||
}
|
||||
|
||||
countEventRow := testCRDBClient.QueryRow("SELECT COUNT(*) FROM eventstore.events where aggregate_type = $1 AND aggregate_id = ANY($2)", tt.res.eventsRes.aggType, pq.Array(tt.res.eventsRes.aggID))
|
||||
countEventRow := testCRDBClient.QueryRow("SELECT COUNT(*) FROM eventstore.events where aggregate_type = $1 AND aggregate_id = ANY($2)", tt.res.eventsRes.aggType, tt.res.eventsRes.aggID)
|
||||
var eventCount int
|
||||
err := countEventRow.Scan(&eventCount)
|
||||
if err != nil {
|
||||
@ -462,8 +461,8 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
|
||||
}
|
||||
type eventsRes struct {
|
||||
pushedEventsCount int
|
||||
aggType []repository.AggregateType
|
||||
aggID []string
|
||||
aggType database.StringArray
|
||||
aggID database.StringArray
|
||||
}
|
||||
type res struct {
|
||||
wantErr bool
|
||||
@ -487,7 +486,7 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
|
||||
eventsRes: eventsRes{
|
||||
pushedEventsCount: 2,
|
||||
aggID: []string{"100", "101"},
|
||||
aggType: []repository.AggregateType{repository.AggregateType(t.Name())},
|
||||
aggType: database.StringArray{t.Name()},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -506,7 +505,7 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
|
||||
eventsRes: eventsRes{
|
||||
pushedEventsCount: 4,
|
||||
aggID: []string{"102", "103"},
|
||||
aggType: []repository.AggregateType{repository.AggregateType(t.Name())},
|
||||
aggType: database.StringArray{t.Name()},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -533,7 +532,7 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
|
||||
eventsRes: eventsRes{
|
||||
pushedEventsCount: 12,
|
||||
aggID: []string{"106", "107", "108"},
|
||||
aggType: []repository.AggregateType{repository.AggregateType(t.Name())},
|
||||
aggType: database.StringArray{t.Name()},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -547,7 +546,7 @@ func TestCRDB_Push_MultipleAggregate(t *testing.T) {
|
||||
t.Errorf("CRDB.Push() error = %v, wantErr %v", err, tt.res.wantErr)
|
||||
}
|
||||
|
||||
countRow := testCRDBClient.QueryRow("SELECT COUNT(*) FROM eventstore.events where aggregate_type = ANY($1) AND aggregate_id = ANY($2)", pq.Array(tt.res.eventsRes.aggType), pq.Array(tt.res.eventsRes.aggID))
|
||||
countRow := testCRDBClient.QueryRow("SELECT COUNT(*) FROM eventstore.events where aggregate_type = ANY($1) AND aggregate_id = ANY($2)", tt.res.eventsRes.aggType, tt.res.eventsRes.aggID)
|
||||
var count int
|
||||
err := countRow.Scan(&count)
|
||||
if err != nil {
|
||||
@ -645,8 +644,8 @@ func TestCRDB_Push_Parallel(t *testing.T) {
|
||||
}
|
||||
type eventsRes struct {
|
||||
pushedEventsCount int
|
||||
aggTypes []repository.AggregateType
|
||||
aggIDs []string
|
||||
aggTypes database.StringArray
|
||||
aggIDs database.StringArray
|
||||
}
|
||||
type res struct {
|
||||
errCount int
|
||||
@ -681,7 +680,7 @@ func TestCRDB_Push_Parallel(t *testing.T) {
|
||||
eventsRes: eventsRes{
|
||||
aggIDs: []string{"200", "201", "202", "203"},
|
||||
pushedEventsCount: 9,
|
||||
aggTypes: []repository.AggregateType{repository.AggregateType(t.Name())},
|
||||
aggTypes: database.StringArray{t.Name()},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -718,7 +717,7 @@ func TestCRDB_Push_Parallel(t *testing.T) {
|
||||
eventsRes: eventsRes{
|
||||
aggIDs: []string{"204", "205", "206"},
|
||||
pushedEventsCount: 14,
|
||||
aggTypes: []repository.AggregateType{repository.AggregateType(t.Name())},
|
||||
aggTypes: database.StringArray{t.Name()},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -748,7 +747,7 @@ func TestCRDB_Push_Parallel(t *testing.T) {
|
||||
eventsRes: eventsRes{
|
||||
aggIDs: []string{"207", "208"},
|
||||
pushedEventsCount: 11,
|
||||
aggTypes: []repository.AggregateType{repository.AggregateType(t.Name())},
|
||||
aggTypes: database.StringArray{t.Name()},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -781,7 +780,7 @@ func TestCRDB_Push_Parallel(t *testing.T) {
|
||||
t.Errorf("CRDB.Push() error count = %d, wanted err count %d, errs: %v", len(errs), tt.res.errCount, errs)
|
||||
}
|
||||
|
||||
rows, err := testCRDBClient.Query("SELECT event_data FROM eventstore.events where aggregate_type = ANY($1) AND aggregate_id = ANY($2) order by event_sequence", pq.Array(tt.res.eventsRes.aggTypes), pq.Array(tt.res.eventsRes.aggIDs))
|
||||
rows, err := testCRDBClient.Query("SELECT event_data FROM eventstore.events where aggregate_type = ANY($1) AND aggregate_id = ANY($2) order by event_sequence", tt.res.eventsRes.aggTypes, tt.res.eventsRes.aggIDs)
|
||||
if err != nil {
|
||||
t.Error("unable to query inserted rows: ", err)
|
||||
return
|
||||
@ -993,10 +992,10 @@ func TestCRDB_Push_ResourceOwner(t *testing.T) {
|
||||
events []*repository.Event
|
||||
}
|
||||
type res struct {
|
||||
resourceOwners []string
|
||||
resourceOwners database.StringArray
|
||||
}
|
||||
type fields struct {
|
||||
aggregateIDs []string
|
||||
aggregateIDs database.StringArray
|
||||
aggregateType string
|
||||
}
|
||||
tests := []struct {
|
||||
@ -1128,7 +1127,7 @@ func TestCRDB_Push_ResourceOwner(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := testCRDBClient.Query("SELECT resource_owner FROM eventstore.events WHERE aggregate_type = $1 AND aggregate_id = ANY($2) ORDER BY event_sequence", tt.fields.aggregateType, pq.Array(tt.fields.aggregateIDs))
|
||||
rows, err := testCRDBClient.Query("SELECT resource_owner FROM eventstore.events WHERE aggregate_type = $1 AND aggregate_id = ANY($2) ORDER BY event_sequence", tt.fields.aggregateType, tt.fields.aggregateIDs)
|
||||
if err != nil {
|
||||
t.Error("unable to query inserted rows: ", err)
|
||||
return
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/cmd/initialise"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/database/cockroach"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -42,15 +44,22 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func initDB(db *sql.DB) error {
|
||||
username := "zitadel"
|
||||
database := "zitadel"
|
||||
err := initialise.Initialise(db, initialise.VerifyUser(username, ""),
|
||||
initialise.VerifyDatabase(database),
|
||||
initialise.VerifyGrant(database, username))
|
||||
config := new(database.Config)
|
||||
config.SetConnector(&cockroach.Config{User: cockroach.User{Username: "zitadel"}, Database: "zitadel"})
|
||||
|
||||
if err := initialise.ReadStmts("cockroach"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := initialise.Init(db,
|
||||
initialise.VerifyUser(config.Username(), ""),
|
||||
initialise.VerifyDatabase(config.Database()),
|
||||
initialise.VerifyGrant(config.Database(), config.Username()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return initialise.VerifyZitadel(db)
|
||||
|
||||
return initialise.VerifyZitadel(db, *config)
|
||||
}
|
||||
|
||||
func fillUniqueData(unique_type, field, instanceID string) error {
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
z_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
@ -170,8 +169,6 @@ func prepareCondition(criteria querier, filters [][]*repository.Filter) (clause
|
||||
for _, f := range filter {
|
||||
value := f.Value
|
||||
switch value.(type) {
|
||||
case []bool, []float64, []int64, []string, []repository.AggregateType, []repository.EventType, *[]bool, *[]float64, *[]int64, *[]string, *[]repository.AggregateType, *[]repository.EventType:
|
||||
value = pq.Array(value)
|
||||
case map[string]interface{}:
|
||||
var err error
|
||||
value, err = json.Marshal(value)
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
@ -265,7 +264,7 @@ func Test_prepareCondition(t *testing.T) {
|
||||
},
|
||||
res: res{
|
||||
clause: " WHERE ( aggregate_type = ANY(?) )",
|
||||
values: []interface{}{pq.Array([]repository.AggregateType{"user", "org"})},
|
||||
values: []interface{}{[]repository.AggregateType{"user", "org"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -281,7 +280,7 @@ func Test_prepareCondition(t *testing.T) {
|
||||
},
|
||||
res: res{
|
||||
clause: " WHERE ( aggregate_type = ANY(?) AND aggregate_id = ? AND event_type = ANY(?) )",
|
||||
values: []interface{}{pq.Array([]repository.AggregateType{"user", "org"}), "1234", pq.Array([]repository.EventType{"user.created", "org.created"})},
|
||||
values: []interface{}{[]repository.AggregateType{"user", "org"}, "1234", []repository.EventType{"user.created", "org.created"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package eventstore
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
@ -262,7 +263,7 @@ func (query *SearchQuery) aggregateIDFilter() *repository.Filter {
|
||||
if len(query.aggregateIDs) == 1 {
|
||||
return repository.NewFilter(repository.FieldAggregateID, query.aggregateIDs[0], repository.OperationEquals)
|
||||
}
|
||||
return repository.NewFilter(repository.FieldAggregateID, query.aggregateIDs, repository.OperationIn)
|
||||
return repository.NewFilter(repository.FieldAggregateID, database.StringArray(query.aggregateIDs), repository.OperationIn)
|
||||
}
|
||||
|
||||
func (query *SearchQuery) eventTypeFilter() *repository.Filter {
|
||||
@ -272,9 +273,9 @@ func (query *SearchQuery) eventTypeFilter() *repository.Filter {
|
||||
if len(query.eventTypes) == 1 {
|
||||
return repository.NewFilter(repository.FieldEventType, repository.EventType(query.eventTypes[0]), repository.OperationEquals)
|
||||
}
|
||||
eventTypes := make([]repository.EventType, len(query.eventTypes))
|
||||
eventTypes := make(database.StringArray, len(query.eventTypes))
|
||||
for i, eventType := range query.eventTypes {
|
||||
eventTypes[i] = repository.EventType(eventType)
|
||||
eventTypes[i] = string(eventType)
|
||||
}
|
||||
return repository.NewFilter(repository.FieldEventType, eventTypes, repository.OperationIn)
|
||||
}
|
||||
@ -286,9 +287,9 @@ func (query *SearchQuery) aggregateTypeFilter() *repository.Filter {
|
||||
if len(query.aggregateTypes) == 1 {
|
||||
return repository.NewFilter(repository.FieldAggregateType, repository.AggregateType(query.aggregateTypes[0]), repository.OperationEquals)
|
||||
}
|
||||
aggregateTypes := make([]repository.AggregateType, len(query.aggregateTypes))
|
||||
aggregateTypes := make(database.StringArray, len(query.aggregateTypes))
|
||||
for i, aggregateType := range query.aggregateTypes {
|
||||
aggregateTypes[i] = repository.AggregateType(aggregateType)
|
||||
aggregateTypes[i] = string(aggregateType)
|
||||
}
|
||||
return repository.NewFilter(repository.FieldAggregateType, aggregateTypes, repository.OperationIn)
|
||||
}
|
||||
@ -326,7 +327,7 @@ func (query *SearchQuery) excludedInstanceIDFilter() *repository.Filter {
|
||||
if len(query.excludedInstanceIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return repository.NewFilter(repository.FieldInstanceID, query.excludedInstanceIDs, repository.OperationNotIn)
|
||||
return repository.NewFilter(repository.FieldInstanceID, database.StringArray(query.excludedInstanceIDs), repository.OperationNotIn)
|
||||
}
|
||||
|
||||
func (builder *SearchQueryBuilder) resourceOwnerFilter() *repository.Filter {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
@ -312,7 +313,7 @@ func TestSearchQuerybuilderBuild(t *testing.T) {
|
||||
Limit: 0,
|
||||
Filters: [][]*repository.Filter{
|
||||
{
|
||||
repository.NewFilter(repository.FieldAggregateType, []repository.AggregateType{"user", "org"}, repository.OperationIn),
|
||||
repository.NewFilter(repository.FieldAggregateType, database.StringArray{"user", "org"}, repository.OperationIn),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -483,7 +484,7 @@ func TestSearchQuerybuilderBuild(t *testing.T) {
|
||||
Filters: [][]*repository.Filter{
|
||||
{
|
||||
repository.NewFilter(repository.FieldAggregateType, repository.AggregateType("user"), repository.OperationEquals),
|
||||
repository.NewFilter(repository.FieldAggregateID, []string{"1234", "0815"}, repository.OperationIn),
|
||||
repository.NewFilter(repository.FieldAggregateID, database.StringArray{"1234", "0815"}, repository.OperationIn),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -561,7 +562,7 @@ func TestSearchQuerybuilderBuild(t *testing.T) {
|
||||
Filters: [][]*repository.Filter{
|
||||
{
|
||||
repository.NewFilter(repository.FieldAggregateType, repository.AggregateType("user"), repository.OperationEquals),
|
||||
repository.NewFilter(repository.FieldEventType, []repository.EventType{"user.created", "user.changed"}, repository.OperationIn),
|
||||
repository.NewFilter(repository.FieldEventType, database.StringArray{"user.created", "user.changed"}, repository.OperationIn),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -740,10 +741,10 @@ func assertRepoQuery(t *testing.T, want, got *repository.SearchQuery) {
|
||||
if !reflect.DeepEqual(got.Columns, want.Columns) {
|
||||
t.Errorf("wrong columns in query: got: %v want: %v", got.Columns, want.Columns)
|
||||
}
|
||||
if !reflect.DeepEqual(got.Desc, want.Desc) {
|
||||
if got.Desc != want.Desc {
|
||||
t.Errorf("wrong desc in query: got: %v want: %v", got.Desc, want.Desc)
|
||||
}
|
||||
if !reflect.DeepEqual(got.Limit, want.Limit) {
|
||||
if got.Limit != want.Limit {
|
||||
t.Errorf("wrong limit in query: got: %v want: %v", got.Limit, want.Limit)
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@ package sql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func Start(client *sql.DB) *SQL {
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
z_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
@ -72,10 +71,6 @@ func prepareCondition(filters [][]*es_models.Filter) (clause string, values []in
|
||||
subClauses := make([]string, 0, len(filter))
|
||||
for _, f := range filter {
|
||||
value := f.GetValue()
|
||||
switch value.(type) {
|
||||
case []bool, []float64, []int64, []string, []es_models.AggregateType, []es_models.EventType, *[]bool, *[]float64, *[]int64, *[]string, *[]es_models.AggregateType, *[]es_models.EventType:
|
||||
value = pq.Array(value)
|
||||
}
|
||||
|
||||
subClauses = append(subClauses, getCondition(f))
|
||||
if subClauses[len(subClauses)-1] == "" {
|
||||
|
@ -6,8 +6,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
)
|
||||
@ -365,7 +363,7 @@ func Test_prepareCondition(t *testing.T) {
|
||||
},
|
||||
res: res{
|
||||
clause: " WHERE ( aggregate_type = ANY(?) )",
|
||||
values: []interface{}{pq.Array([]es_models.AggregateType{"user", "org"})},
|
||||
values: []interface{}{[]es_models.AggregateType{"user", "org"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -381,7 +379,7 @@ func Test_prepareCondition(t *testing.T) {
|
||||
},
|
||||
res: res{
|
||||
clause: " WHERE ( aggregate_type = ANY(?) AND aggregate_id = ? AND event_type = ANY(?) )",
|
||||
values: []interface{}{pq.Array([]es_models.AggregateType{"user", "org"}), "1234", pq.Array([]es_models.EventType{"user.created", "org.created"})},
|
||||
values: []interface{}{[]es_models.AggregateType{"user", "org"}, "1234", []es_models.EventType{"user.created", "org.created"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -3,9 +3,6 @@ package sql
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
//sql import
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
type SQL struct {
|
||||
|
@ -31,7 +31,7 @@ func Renew(dbClient *sql.DB, lockTable, lockerID, viewModel, instanceID string,
|
||||
return crdb.ExecuteTx(context.Background(), dbClient, nil, func(tx *sql.Tx) error {
|
||||
insert := fmt.Sprintf(insertStmtFormat, lockTable)
|
||||
result, err := tx.Exec(insert,
|
||||
lockerID, waitTime.Milliseconds()/millisecondsAsSeconds, viewModel, instanceID)
|
||||
lockerID, waitTime, viewModel, instanceID)
|
||||
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -38,7 +38,12 @@ func ReduceEvent(handler Handler, event *models.Event) {
|
||||
|
||||
if err != nil {
|
||||
handler.Subscription().Unsubscribe()
|
||||
logging.WithFields("cause", err, "stack", string(debug.Stack())).Error("reduce panicked")
|
||||
logging.WithFields(
|
||||
"cause", err,
|
||||
"stack", string(debug.Stack()),
|
||||
"sequence", event.Sequence,
|
||||
"instnace", event.InstanceID,
|
||||
).Error("reduce panicked")
|
||||
}
|
||||
}()
|
||||
currentSequence, err := handler.CurrentSequence(event.InstanceID)
|
||||
|
@ -75,7 +75,10 @@ func (s *spooledHandler) load(workerID string) {
|
||||
err := recover()
|
||||
|
||||
if err != nil {
|
||||
logging.WithFields("cause", err, "stack", string(debug.Stack())).Error("reduce panicked")
|
||||
logging.WithFields(
|
||||
"cause", err,
|
||||
"stack", string(debug.Stack()),
|
||||
).Error("reduce panicked")
|
||||
}
|
||||
}()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
@ -5,11 +5,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
@ -40,7 +40,7 @@ type IDPConfigView struct {
|
||||
OIDCClientID string `json:"clientId" gorm:"column:oidc_client_id"`
|
||||
OIDCClientSecret *crypto.CryptoValue `json:"clientSecret" gorm:"column:oidc_client_secret"`
|
||||
OIDCIssuer string `json:"issuer" gorm:"column:oidc_issuer"`
|
||||
OIDCScopes pq.StringArray `json:"scopes" gorm:"column:oidc_scopes"`
|
||||
OIDCScopes database.StringArray `json:"scopes" gorm:"column:oidc_scopes"`
|
||||
OIDCIDPDisplayNameMapping int32 `json:"idpDisplayNameMapping" gorm:"column:oidc_idp_display_name_mapping"`
|
||||
OIDCUsernameMapping int32 `json:"usernameMapping" gorm:"column:oidc_idp_username_mapping"`
|
||||
OAuthAuthorizationEndpoint string `json:"authorizationEndpoint" gorm:"column:oauth_authorization_endpoint"`
|
||||
|
@ -88,7 +88,7 @@ func isPrivateIPv4(ip net.IP) bool {
|
||||
|
||||
func machineID() (uint16, error) {
|
||||
if GeneratorConfig == nil {
|
||||
return 0, errors.New("Cannot create a unique ID for the machine, generator has not been configured.")
|
||||
return 0, errors.New("cannot create a unique id for the machine, generator has not been configured")
|
||||
}
|
||||
|
||||
errors := []string{}
|
||||
|
@ -4,10 +4,10 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -40,17 +40,17 @@ type ApplicationView struct {
|
||||
IsOIDC bool `json:"-" gorm:"column:is_oidc"`
|
||||
OIDCVersion int32 `json:"oidcVersion" gorm:"column:oidc_version"`
|
||||
OIDCClientID string `json:"clientId" gorm:"column:oidc_client_id"`
|
||||
OIDCRedirectUris pq.StringArray `json:"redirectUris" gorm:"column:oidc_redirect_uris"`
|
||||
OIDCResponseTypes pq.Int64Array `json:"responseTypes" gorm:"column:oidc_response_types"`
|
||||
OIDCGrantTypes pq.Int64Array `json:"grantTypes" gorm:"column:oidc_grant_types"`
|
||||
OIDCRedirectUris database.StringArray `json:"redirectUris" gorm:"column:oidc_redirect_uris"`
|
||||
OIDCResponseTypes database.EnumArray[domain.OIDCResponseType] `json:"responseTypes" gorm:"column:oidc_response_types"`
|
||||
OIDCGrantTypes database.EnumArray[domain.OIDCGrantType] `json:"grantTypes" gorm:"column:oidc_grant_types"`
|
||||
OIDCApplicationType int32 `json:"applicationType" gorm:"column:oidc_application_type"`
|
||||
OIDCAuthMethodType int32 `json:"authMethodType" gorm:"column:oidc_auth_method_type"`
|
||||
OIDCPostLogoutRedirectUris pq.StringArray `json:"postLogoutRedirectUris" gorm:"column:oidc_post_logout_redirect_uris"`
|
||||
OIDCPostLogoutRedirectUris database.StringArray `json:"postLogoutRedirectUris" gorm:"column:oidc_post_logout_redirect_uris"`
|
||||
NoneCompliant bool `json:"-" gorm:"column:none_compliant"`
|
||||
ComplianceProblems pq.StringArray `json:"-" gorm:"column:compliance_problems"`
|
||||
ComplianceProblems database.StringArray `json:"-" gorm:"column:compliance_problems"`
|
||||
DevMode bool `json:"devMode" gorm:"column:dev_mode"`
|
||||
OriginAllowList pq.StringArray `json:"-" gorm:"column:origin_allow_list"`
|
||||
AdditionalOrigins pq.StringArray `json:"additionalOrigins" gorm:"column:additional_origins"`
|
||||
OriginAllowList database.StringArray `json:"-" gorm:"column:origin_allow_list"`
|
||||
AdditionalOrigins database.StringArray `json:"additionalOrigins" gorm:"column:additional_origins"`
|
||||
AccessTokenType int32 `json:"accessTokenType" gorm:"column:access_token_type"`
|
||||
AccessTokenRoleAssertion bool `json:"accessTokenRoleAssertion" gorm:"column:access_token_role_assertion"`
|
||||
IDTokenRoleAssertion bool `json:"idTokenRoleAssertion" gorm:"column:id_token_role_assertion"`
|
||||
@ -60,7 +60,7 @@ type ApplicationView struct {
|
||||
Sequence uint64 `json:"-" gorm:"sequence"`
|
||||
}
|
||||
|
||||
func OIDCResponseTypesToModel(oidctypes []int64) []model.OIDCResponseType {
|
||||
func OIDCResponseTypesToModel(oidctypes []domain.OIDCResponseType) []model.OIDCResponseType {
|
||||
result := make([]model.OIDCResponseType, len(oidctypes))
|
||||
for i, t := range oidctypes {
|
||||
result[i] = model.OIDCResponseType(t)
|
||||
@ -68,7 +68,7 @@ func OIDCResponseTypesToModel(oidctypes []int64) []model.OIDCResponseType {
|
||||
return result
|
||||
}
|
||||
|
||||
func OIDCGrantTypesToModel(granttypes []int64) []model.OIDCGrantType {
|
||||
func OIDCGrantTypesToModel(granttypes []domain.OIDCGrantType) []model.OIDCGrantType {
|
||||
result := make([]model.OIDCGrantType, len(granttypes))
|
||||
for i, t := range granttypes {
|
||||
result[i] = model.OIDCGrantType(t)
|
||||
@ -169,7 +169,7 @@ func (a *ApplicationView) SetData(event *models.Event) error {
|
||||
}
|
||||
|
||||
func (a *ApplicationView) setOriginAllowList() error {
|
||||
allowList := make([]string, 0)
|
||||
allowList := make(database.StringArray, 0)
|
||||
for _, redirect := range a.OIDCRedirectUris {
|
||||
origin, err := http_util.GetOriginFromURLString(redirect)
|
||||
if err != nil {
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
@ -35,7 +35,7 @@ type ProjectGrantView struct {
|
||||
ResourceOwnerName string `json:"-" gorm:"column:resource_owner_name"`
|
||||
OrgName string `json:"-" gorm:"column:org_name"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
GrantedRoleKeys pq.StringArray `json:"-" gorm:"column:granted_role_keys"`
|
||||
GrantedRoleKeys database.StringArray `json:"-" gorm:"column:granted_role_keys"`
|
||||
}
|
||||
|
||||
type ProjectGrant struct {
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
@ -32,7 +32,7 @@ type ProjectGrantMemberView struct {
|
||||
FirstName string `json:"-" gorm:"column:first_name"`
|
||||
LastName string `json:"-" gorm:"column:last_name"`
|
||||
DisplayName string `json:"-" gorm:"column:display_name"`
|
||||
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
|
||||
Roles database.StringArray `json:"roles" gorm:"column:roles"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
|
||||
AvatarKey string `json:"-" gorm:"column:avatar_key"`
|
||||
|
@ -5,8 +5,6 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
@ -30,18 +28,18 @@ func TestGrantedProjectMemberAppendEvent(t *testing.T) {
|
||||
{
|
||||
name: "append added member event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantMemberAddedType), ResourceOwner: "OrgID", Data: mockProjectGrantMemberData(&es_model.ProjectGrantMember{GrantID: "ProjectGrantID", UserID: "UserID", Roles: pq.StringArray{"Role"}})},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantMemberAddedType), ResourceOwner: "OrgID", Data: mockProjectGrantMemberData(&es_model.ProjectGrantMember{GrantID: "ProjectGrantID", UserID: "UserID", Roles: []string{"Role"}})},
|
||||
member: &ProjectGrantMemberView{},
|
||||
},
|
||||
result: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: pq.StringArray{"Role"}},
|
||||
result: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: []string{"Role"}},
|
||||
},
|
||||
{
|
||||
name: "append changed member event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantMemberAddedType), ResourceOwner: "OrgID", Data: mockProjectGrantMemberData(&es_model.ProjectGrantMember{GrantID: "ProjectGrantID", Roles: pq.StringArray{"RoleChanged"}})},
|
||||
member: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: pq.StringArray{"Role"}},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantMemberAddedType), ResourceOwner: "OrgID", Data: mockProjectGrantMemberData(&es_model.ProjectGrantMember{GrantID: "ProjectGrantID", Roles: []string{"RoleChanged"}})},
|
||||
member: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: []string{"Role"}},
|
||||
},
|
||||
result: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: pq.StringArray{"RoleChanged"}},
|
||||
result: &ProjectGrantMemberView{ProjectID: "AggregateID", UserID: "UserID", GrantID: "ProjectGrantID", Roles: []string{"RoleChanged"}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@ -5,8 +5,6 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
"github.com/zitadel/zitadel/internal/project/model"
|
||||
es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model"
|
||||
@ -36,34 +34,34 @@ func TestProjectGrantAppendEvent(t *testing.T) {
|
||||
{
|
||||
name: "append added project grant event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantAddedType), ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID", GrantedOrgID: "GrantedOrgID", RoleKeys: pq.StringArray{"Role"}})},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantAddedType), ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID", GrantedOrgID: "GrantedOrgID", RoleKeys: []string{"Role"}})},
|
||||
project: &ProjectGrantView{},
|
||||
},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: pq.StringArray{"Role"}},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}},
|
||||
},
|
||||
{
|
||||
name: "append change project grant event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantChangedType), ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID", RoleKeys: pq.StringArray{"RoleChanged"}})},
|
||||
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: pq.StringArray{"Role"}},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantChangedType), ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID", RoleKeys: []string{"RoleChanged"}})},
|
||||
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}},
|
||||
},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: pq.StringArray{"RoleChanged"}},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"RoleChanged"}},
|
||||
},
|
||||
{
|
||||
name: "append deactivate project grant event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantDeactivatedType), ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID"})},
|
||||
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: pq.StringArray{"Role"}},
|
||||
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}},
|
||||
},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateInactive), GrantedRoleKeys: pq.StringArray{"Role"}},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateInactive), GrantedRoleKeys: []string{"Role"}},
|
||||
},
|
||||
{
|
||||
name: "append reactivate project grant event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.GrantReactivatedType), ResourceOwner: "GrantedOrgID", Data: mockProjectGrantData(&es_model.ProjectGrant{GrantID: "ProjectGrantID"})},
|
||||
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateInactive), GrantedRoleKeys: pq.StringArray{"Role"}},
|
||||
project: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateInactive), GrantedRoleKeys: []string{"Role"}},
|
||||
},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: pq.StringArray{"Role"}},
|
||||
result: &ProjectGrantView{ProjectID: "AggregateID", ResourceOwner: "GrantedOrgID", OrgID: "GrantedOrgID", State: int32(model.ProjectStateActive), GrantedRoleKeys: []string{"Role"}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
@ -30,7 +30,7 @@ type ProjectMemberView struct {
|
||||
FirstName string `json:"-" gorm:"column:first_name"`
|
||||
LastName string `json:"-" gorm:"column:last_name"`
|
||||
DisplayName string `json:"-" gorm:"column:display_name"`
|
||||
Roles pq.StringArray `json:"roles" gorm:"column:roles"`
|
||||
Roles database.StringArray `json:"roles" gorm:"column:roles"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
PreferredLoginName string `json:"-" gorm:"column:preferred_login_name"`
|
||||
AvatarKey string `json:"-" gorm:"column:avatar_key"`
|
||||
|
@ -5,8 +5,6 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
@ -30,18 +28,18 @@ func TestProjectMemberAppendEvent(t *testing.T) {
|
||||
{
|
||||
name: "append added member event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.MemberAddedType), ResourceOwner: "OrgID", Data: mockProjectMemberData(&es_model.ProjectMember{UserID: "UserID", Roles: pq.StringArray{"Role"}})},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.MemberAddedType), ResourceOwner: "OrgID", Data: mockProjectMemberData(&es_model.ProjectMember{UserID: "UserID", Roles: []string{"Role"}})},
|
||||
member: &ProjectMemberView{},
|
||||
},
|
||||
result: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: pq.StringArray{"Role"}},
|
||||
result: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: []string{"Role"}},
|
||||
},
|
||||
{
|
||||
name: "append changed member event",
|
||||
args: args{
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.MemberAddedType), ResourceOwner: "OrgID", Data: mockProjectMemberData(&es_model.ProjectMember{UserID: "UserID", Roles: pq.StringArray{"RoleChanged"}})},
|
||||
member: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: pq.StringArray{"Role"}},
|
||||
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_models.EventType(project.MemberAddedType), ResourceOwner: "OrgID", Data: mockProjectMemberData(&es_model.ProjectMember{UserID: "UserID", Roles: []string{"RoleChanged"}})},
|
||||
member: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: []string{"Role"}},
|
||||
},
|
||||
result: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: pq.StringArray{"RoleChanged"}},
|
||||
result: &ProjectMemberView{ProjectID: "AggregateID", UserID: "UserID", Roles: []string{"RoleChanged"}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
|
||||
@ -216,8 +215,8 @@ func prepareFlowQuery(flowType domain.FlowType) (sq.SelectBuilder, func(*sql.Row
|
||||
for rows.Next() {
|
||||
var (
|
||||
actionID sql.NullString
|
||||
actionCreationDate pq.NullTime
|
||||
actionChangeDate pq.NullTime
|
||||
actionCreationDate sql.NullTime
|
||||
actionChangeDate sql.NullTime
|
||||
actionResourceOwner sql.NullString
|
||||
actionState sql.NullInt32
|
||||
actionSequence sql.NullInt64
|
||||
|
@ -31,14 +31,14 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.flows_triggers.trigger_type,`+
|
||||
` projections.flows_triggers.trigger_sequence,`+
|
||||
` projections.flows_triggers.flow_type,`+
|
||||
@ -46,7 +46,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` projections.flows_triggers.sequence,`+
|
||||
` projections.flows_triggers.resource_owner`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -63,14 +63,14 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.flows_triggers.trigger_type,`+
|
||||
` projections.flows_triggers.trigger_sequence,`+
|
||||
` projections.flows_triggers.flow_type,`+
|
||||
@ -78,7 +78,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` projections.flows_triggers.sequence,`+
|
||||
` projections.flows_triggers.resource_owner`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -144,14 +144,14 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.flows_triggers.trigger_type,`+
|
||||
` projections.flows_triggers.trigger_sequence,`+
|
||||
` projections.flows_triggers.flow_type,`+
|
||||
@ -159,7 +159,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` projections.flows_triggers.sequence,`+
|
||||
` projections.flows_triggers.resource_owner`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -253,14 +253,14 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.flows_triggers.trigger_type,`+
|
||||
` projections.flows_triggers.trigger_sequence,`+
|
||||
` projections.flows_triggers.flow_type,`+
|
||||
@ -268,7 +268,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` projections.flows_triggers.sequence,`+
|
||||
` projections.flows_triggers.resource_owner`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -321,14 +321,14 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
},
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.flows_triggers.trigger_type,`+
|
||||
` projections.flows_triggers.trigger_sequence,`+
|
||||
` projections.flows_triggers.flow_type,`+
|
||||
@ -336,7 +336,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` projections.flows_triggers.sequence,`+
|
||||
` projections.flows_triggers.resource_owner`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -353,16 +353,16 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -374,16 +374,16 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -426,16 +426,16 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -498,16 +498,16 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
prepare: prepareTriggerActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script`+
|
||||
` FROM projections.flows_triggers`+
|
||||
` LEFT JOIN projections.actions ON projections.flows_triggers.action_id = projections.actions.id`),
|
||||
` LEFT JOIN projections.actions2 ON projections.flows_triggers.action_id = projections.actions2.id`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
|
@ -29,18 +29,18 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
` projections.actions.timeout,`+
|
||||
` projections.actions.allowed_to_fail,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.actions2.timeout,`+
|
||||
` projections.actions2.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions`),
|
||||
` FROM projections.actions2`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -52,18 +52,18 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
` projections.actions.timeout,`+
|
||||
` projections.actions.allowed_to_fail,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.actions2.timeout,`+
|
||||
` projections.actions2.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions`),
|
||||
` FROM projections.actions2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -118,18 +118,18 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
` projections.actions.timeout,`+
|
||||
` projections.actions.allowed_to_fail,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.actions2.timeout,`+
|
||||
` projections.actions2.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions`),
|
||||
` FROM projections.actions2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -208,18 +208,18 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionsQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
` projections.actions.timeout,`+
|
||||
` projections.actions.allowed_to_fail,`+
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.actions2.timeout,`+
|
||||
` projections.actions2.allowed_to_fail,`+
|
||||
` COUNT(*) OVER ()`+
|
||||
` FROM projections.actions`),
|
||||
` FROM projections.actions2`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
@ -236,17 +236,17 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
` projections.actions.timeout,`+
|
||||
` projections.actions.allowed_to_fail`+
|
||||
` FROM projections.actions`),
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.actions2.timeout,`+
|
||||
` projections.actions2.allowed_to_fail`+
|
||||
` FROM projections.actions2`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@ -264,17 +264,17 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
` projections.actions.timeout,`+
|
||||
` projections.actions.allowed_to_fail`+
|
||||
` FROM projections.actions`),
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.actions2.timeout,`+
|
||||
` projections.actions2.allowed_to_fail`+
|
||||
` FROM projections.actions2`),
|
||||
[]string{
|
||||
"id",
|
||||
"creation_date",
|
||||
@ -319,17 +319,17 @@ func Test_ActionPrepares(t *testing.T) {
|
||||
prepare: prepareActionQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(`SELECT projections.actions.id,`+
|
||||
` projections.actions.creation_date,`+
|
||||
` projections.actions.change_date,`+
|
||||
` projections.actions.resource_owner,`+
|
||||
` projections.actions.sequence,`+
|
||||
` projections.actions.action_state,`+
|
||||
` projections.actions.name,`+
|
||||
` projections.actions.script,`+
|
||||
` projections.actions.timeout,`+
|
||||
` projections.actions.allowed_to_fail`+
|
||||
` FROM projections.actions`),
|
||||
regexp.QuoteMeta(`SELECT projections.actions2.id,`+
|
||||
` projections.actions2.creation_date,`+
|
||||
` projections.actions2.change_date,`+
|
||||
` projections.actions2.resource_owner,`+
|
||||
` projections.actions2.sequence,`+
|
||||
` projections.actions2.action_state,`+
|
||||
` projections.actions2.name,`+
|
||||
` projections.actions2.script,`+
|
||||
` projections.actions2.timeout,`+
|
||||
` projections.actions2.allowed_to_fail`+
|
||||
` FROM projections.actions2`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user