mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 11:17:32 +00:00
fixup! fixup! Merge branch 'main' into import_export_merge
This commit is contained in:
@@ -9,16 +9,16 @@ import (
|
||||
)
|
||||
|
||||
type Instance struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
DefaultOrgID string `json:"default_org_id"`
|
||||
IAMProjectID string `json:"iam_project_id"`
|
||||
ConsoleClientId string `json:"console_client_id"`
|
||||
ConsoleAppID string `json:"console_app_id"`
|
||||
DefaultLanguage string `json:"default_language"`
|
||||
CreatedAt time.Time `json:"-"`
|
||||
UpdatedAt time.Time `json:"-"`
|
||||
DeletedAt *time.Time `json:"-"`
|
||||
ID string `json:"id,omitempty" db:"id"`
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
DefaultOrgID string `json:"default_org_id,omitempty" db:"default_org_id"`
|
||||
IAMProjectID string `json:"iam_project_id,omitempty" db:"iam_project_id"`
|
||||
ConsoleClientID string `json:"console_client_id,omitempty" db:"console_client_id"`
|
||||
ConsoleAppID string `json:"console_app_id,omitempty" db:"console_app_id"`
|
||||
DefaultLanguage string `json:"default_language,omitempty" db:"default_language"`
|
||||
CreatedAt time.Time `json:"-,omitempty" db:"created_at"`
|
||||
UpdatedAt time.Time `json:"-,omitempty" db:"updated_at"`
|
||||
DeletedAt *time.Time `json:"-,omitempty" db:"deleted_at"`
|
||||
}
|
||||
|
||||
type instanceCacheIndex uint8
|
||||
@@ -44,8 +44,8 @@ type instanceColumns interface {
|
||||
IDColumn() database.Column
|
||||
// NameColumn returns the column for the name field.
|
||||
NameColumn() database.Column
|
||||
// DefaultOrgIdColumn returns the column for the default org id field
|
||||
DefaultOrgIdColumn() database.Column
|
||||
// DefaultOrgIDColumn returns the column for the default org id field
|
||||
DefaultOrgIDColumn() database.Column
|
||||
// IAMProjectIDColumn returns the column for the default IAM org id field
|
||||
IAMProjectIDColumn() database.Column
|
||||
// ConsoleClientIDColumn returns the column for the default IAM org id field
|
||||
@@ -87,9 +87,10 @@ type InstanceRepository interface {
|
||||
// Member() MemberRepository
|
||||
|
||||
Get(ctx context.Context, opts ...database.Condition) (*Instance, error)
|
||||
List(ctx context.Context, opts ...database.Condition) ([]*Instance, error)
|
||||
|
||||
Create(ctx context.Context, instance *Instance) error
|
||||
Update(ctx context.Context, condition database.Condition, changes ...database.Change) error
|
||||
Update(ctx context.Context, condition database.Condition, changes ...database.Change) (int64, error)
|
||||
Delete(ctx context.Context, condition database.Condition) error
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,7 @@ type Querier interface {
|
||||
|
||||
// Executor is a database client that can execute statements.
|
||||
type Executor interface {
|
||||
Exec(ctx context.Context, stmt string, args ...any) error
|
||||
Exec(ctx context.Context, stmt string, args ...any) (int64, error)
|
||||
}
|
||||
|
||||
// QueryExecutor is a database client that can execute queries and statements.
|
||||
|
@@ -13,9 +13,7 @@ type pgxConn struct {
|
||||
*pgxpool.Conn
|
||||
}
|
||||
|
||||
var (
|
||||
_ database.Client = (*pgxConn)(nil)
|
||||
)
|
||||
var _ database.Client = (*pgxConn)(nil)
|
||||
|
||||
// Release implements [database.Client].
|
||||
func (c *pgxConn) Release(_ context.Context) error {
|
||||
@@ -47,9 +45,9 @@ func (c *pgxConn) QueryRow(ctx context.Context, sql string, args ...any) databas
|
||||
|
||||
// Exec implements [database.Pool].
|
||||
// Subtle: this method shadows the method (Pool).Exec of pgxPool.Pool.
|
||||
func (c *pgxConn) Exec(ctx context.Context, sql string, args ...any) error {
|
||||
_, err := c.Conn.Exec(ctx, sql, args...)
|
||||
return err
|
||||
func (c *pgxConn) Exec(ctx context.Context, sql string, args ...any) (int64, error) {
|
||||
res, err := c.Conn.Exec(ctx, sql, args...)
|
||||
return res.RowsAffected(), err
|
||||
}
|
||||
|
||||
// Migrate implements [database.Migrator].
|
||||
|
@@ -1,6 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS zitadel.instances(
|
||||
id TEXT NOT NULL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
id TEXT NOT NULL CHECK (id <> '') PRIMARY KEY,
|
||||
name TEXT NOT NULL CHECK (name <> ''),
|
||||
default_org_id TEXT, -- NOT NULL,
|
||||
iam_project_id TEXT, -- NOT NULL,
|
||||
console_client_id TEXT, -- NOT NULL,
|
||||
|
@@ -45,9 +45,9 @@ func (c *pgxPool) QueryRow(ctx context.Context, sql string, args ...any) databas
|
||||
|
||||
// Exec implements [database.Pool].
|
||||
// Subtle: this method shadows the method (Pool).Exec of pgxPool.Pool.
|
||||
func (c *pgxPool) Exec(ctx context.Context, sql string, args ...any) error {
|
||||
_, err := c.Pool.Exec(ctx, sql, args...)
|
||||
return err
|
||||
func (c *pgxPool) Exec(ctx context.Context, sql string, args ...any) (int64, error) {
|
||||
res, err := c.Pool.Exec(ctx, sql, args...)
|
||||
return res.RowsAffected(), err
|
||||
}
|
||||
|
||||
// Begin implements [database.Pool].
|
||||
|
@@ -46,9 +46,9 @@ func (tx *pgxTx) QueryRow(ctx context.Context, sql string, args ...any) database
|
||||
|
||||
// Exec implements [database.Transaction].
|
||||
// Subtle: this method shadows the method (Pool).Exec of pgxPool.Pool.
|
||||
func (tx *pgxTx) Exec(ctx context.Context, sql string, args ...any) error {
|
||||
_, err := tx.Tx.Exec(ctx, sql, args...)
|
||||
return err
|
||||
func (tx *pgxTx) Exec(ctx context.Context, sql string, args ...any) (int64, error) {
|
||||
res, err := tx.Tx.Exec(ctx, sql, args...)
|
||||
return res.RowsAffected(), err
|
||||
}
|
||||
|
||||
// Begin implements [database.Transaction].
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/zitadel/zitadel/backend/v3/domain"
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
)
|
||||
@@ -37,14 +38,33 @@ func (i *instance) Get(ctx context.Context, opts ...database.Condition) (*domain
|
||||
|
||||
i.builder.WriteString(queryInstanceStmt)
|
||||
|
||||
isNotDeletedCondition := database.IsNull(i.DeletedAtColumn())
|
||||
opts = append(opts, isNotDeletedCondition)
|
||||
opts = append(opts, database.IsNull(i.DeletedAtColumn()))
|
||||
andCondition := database.And(opts...)
|
||||
andCondition.Write(&i.builder)
|
||||
|
||||
return scanInstance(i.client.QueryRow(ctx, i.builder.String(), i.builder.Args()...))
|
||||
}
|
||||
|
||||
// List implements [domain.InstanceRepository].
|
||||
// func (i *instance) List(ctx context.Context, opts ...database.QueryOption) (*domain.Instance, error) {
|
||||
func (i *instance) List(ctx context.Context, opts ...database.Condition) ([]*domain.Instance, error) {
|
||||
i.builder = database.StatementBuilder{}
|
||||
|
||||
i.builder.WriteString(queryInstanceStmt)
|
||||
|
||||
opts = append(opts, database.IsNull(i.DeletedAtColumn()))
|
||||
andCondition := database.And(opts...)
|
||||
andCondition.Write(&i.builder)
|
||||
|
||||
rows, err := i.client.Query(ctx, i.builder.String(), i.builder.Args()...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
return scanInstances(rows)
|
||||
}
|
||||
|
||||
const createInstanceStmt = `INSERT INTO zitadel.instances (id, name, default_org_id, iam_project_id, console_client_id, console_app_id, default_language)` +
|
||||
` VALUES ($1, $2, $3, $4, $5, $6, $7)` +
|
||||
` RETURNING created_at, updated_at`
|
||||
@@ -52,14 +72,35 @@ const createInstanceStmt = `INSERT INTO zitadel.instances (id, name, default_org
|
||||
// Create implements [domain.InstanceRepository].
|
||||
func (i *instance) Create(ctx context.Context, instance *domain.Instance) error {
|
||||
i.builder = database.StatementBuilder{}
|
||||
i.builder.AppendArgs(instance.ID, instance.Name, instance.DefaultOrgID, instance.IAMProjectID, instance.ConsoleClientId, instance.ConsoleAppID, instance.DefaultLanguage)
|
||||
i.builder.AppendArgs(instance.ID, instance.Name, instance.DefaultOrgID, instance.IAMProjectID, instance.ConsoleClientID, instance.ConsoleAppID, instance.DefaultLanguage)
|
||||
i.builder.WriteString(createInstanceStmt)
|
||||
|
||||
return i.client.QueryRow(ctx, i.builder.String(), i.builder.Args()...).Scan(&instance.CreatedAt, &instance.UpdatedAt)
|
||||
err := i.client.QueryRow(ctx, i.builder.String(), i.builder.Args()...).Scan(&instance.CreatedAt, &instance.UpdatedAt)
|
||||
if err != nil {
|
||||
var pgErr *pgconn.PgError
|
||||
if errors.As(err, &pgErr) {
|
||||
// constraint violation
|
||||
if pgErr.Code == "23514" {
|
||||
if pgErr.ConstraintName == "instances_name_check" {
|
||||
return errors.New("instnace name not provided")
|
||||
}
|
||||
if pgErr.ConstraintName == "instances_id_check" {
|
||||
return errors.New("instnace id not provided")
|
||||
}
|
||||
}
|
||||
// duplicate
|
||||
if pgErr.Code == "23505" {
|
||||
if pgErr.ConstraintName == "instances_pkey" {
|
||||
return errors.New("instnace id already exists")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Update implements [domain.InstanceRepository].
|
||||
func (i instance) Update(ctx context.Context, condition database.Condition, changes ...database.Change) error {
|
||||
func (i instance) Update(ctx context.Context, condition database.Condition, changes ...database.Change) (int64, error) {
|
||||
i.builder = database.StatementBuilder{}
|
||||
i.builder.WriteString(`UPDATE zitadel.instances SET `)
|
||||
database.Changes(changes).Write(&i.builder)
|
||||
@@ -67,7 +108,8 @@ func (i instance) Update(ctx context.Context, condition database.Condition, chan
|
||||
|
||||
stmt := i.builder.String()
|
||||
|
||||
return i.client.Exec(ctx, stmt, i.builder.Args()...)
|
||||
rowsAffected, err := i.client.Exec(ctx, stmt, i.builder.Args()...)
|
||||
return rowsAffected, err
|
||||
}
|
||||
|
||||
// Delete implements [domain.InstanceRepository].
|
||||
@@ -80,7 +122,8 @@ func (i instance) Delete(ctx context.Context, condition database.Condition) erro
|
||||
i.builder.AppendArgs(time.Now())
|
||||
|
||||
i.writeCondition(condition)
|
||||
return i.client.Exec(ctx, i.builder.String(), i.builder.Args()...)
|
||||
_, err := i.client.Exec(ctx, i.builder.String(), i.builder.Args()...)
|
||||
return err
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
@@ -126,7 +169,7 @@ func (instance) CreatedAtColumn() database.Column {
|
||||
}
|
||||
|
||||
// DefaultOrgIdColumn implements [domain.instanceColumns].
|
||||
func (instance) DefaultOrgIdColumn() database.Column {
|
||||
func (instance) DefaultOrgIDColumn() database.Column {
|
||||
return database.NewColumn("default_org_id")
|
||||
}
|
||||
|
||||
@@ -175,7 +218,7 @@ func scanInstance(scanner database.Scanner) (*domain.Instance, error) {
|
||||
&instance.Name,
|
||||
&instance.DefaultOrgID,
|
||||
&instance.IAMProjectID,
|
||||
&instance.ConsoleClientId,
|
||||
&instance.ConsoleClientID,
|
||||
&instance.ConsoleAppID,
|
||||
&instance.DefaultLanguage,
|
||||
&instance.CreatedAt,
|
||||
@@ -194,3 +237,30 @@ func scanInstance(scanner database.Scanner) (*domain.Instance, error) {
|
||||
|
||||
return &instance, nil
|
||||
}
|
||||
|
||||
func scanInstances(rows database.Rows) ([]*domain.Instance, error) {
|
||||
instances := make([]*domain.Instance, 0)
|
||||
for rows.Next() {
|
||||
|
||||
var instance domain.Instance
|
||||
err := rows.Scan(
|
||||
&instance.ID,
|
||||
&instance.Name,
|
||||
&instance.DefaultOrgID,
|
||||
&instance.IAMProjectID,
|
||||
&instance.ConsoleClientID,
|
||||
&instance.ConsoleAppID,
|
||||
&instance.DefaultLanguage,
|
||||
&instance.CreatedAt,
|
||||
&instance.UpdatedAt,
|
||||
&instance.DeletedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instances = append(instances, &instance)
|
||||
|
||||
}
|
||||
return instances, nil
|
||||
}
|
||||
|
@@ -2,12 +2,12 @@ package repository_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v6"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/v3/domain"
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
@@ -15,81 +15,363 @@ import (
|
||||
)
|
||||
|
||||
func TestCreateInstance(t *testing.T) {
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
tests := []struct {
|
||||
name string
|
||||
testFunc func() *domain.Instance
|
||||
instance domain.Instance
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
instance: func() domain.Instance {
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
instance := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
return instance
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "create instance wihtout name",
|
||||
instance: func() domain.Instance {
|
||||
instanceId := gofakeit.Name()
|
||||
// instanceName := gofakeit.Name()
|
||||
instance := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: "",
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
return instance
|
||||
}(),
|
||||
err: errors.New("instnace name not provided"),
|
||||
},
|
||||
{
|
||||
name: "adding same instance twice",
|
||||
testFunc: func() *domain.Instance {
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
|
||||
ctx := context.Background()
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientId: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
ctx := context.Background()
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
|
||||
err := instanceRepo.Create(ctx, &inst)
|
||||
assert.NoError(t, err)
|
||||
return &inst
|
||||
},
|
||||
err: errors.New("instnace id already exists"),
|
||||
},
|
||||
{
|
||||
name: "adding instance with no id",
|
||||
instance: func() domain.Instance {
|
||||
// instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
instance := domain.Instance{
|
||||
// ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
return instance
|
||||
}(),
|
||||
err: errors.New("instnace id not provided"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
beforeCreate := time.Now()
|
||||
err := instanceRepo.Create(ctx, &inst)
|
||||
require.NoError(t, err)
|
||||
afterCreate := time.Now()
|
||||
var instance *domain.Instance
|
||||
if tt.testFunc != nil {
|
||||
instance = tt.testFunc()
|
||||
} else {
|
||||
instance = &tt.instance
|
||||
}
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
|
||||
instance, err := instanceRepo.Get(ctx,
|
||||
instanceRepo.NameCondition(database.TextOperationEqual, instanceName),
|
||||
)
|
||||
require.Equal(t, inst.ID, instance.ID)
|
||||
require.Equal(t, inst.Name, instance.Name)
|
||||
require.Equal(t, inst.DefaultOrgID, instance.DefaultOrgID)
|
||||
require.Equal(t, inst.IAMProjectID, instance.IAMProjectID)
|
||||
require.Equal(t, inst.ConsoleClientId, instance.ConsoleClientId)
|
||||
require.Equal(t, inst.ConsoleAppID, instance.ConsoleAppID)
|
||||
require.Equal(t, inst.DefaultLanguage, instance.DefaultLanguage)
|
||||
assert.WithinRange(t, instance.CreatedAt, beforeCreate, afterCreate)
|
||||
assert.WithinRange(t, instance.UpdatedAt, beforeCreate, afterCreate)
|
||||
require.Nil(t, instance.DeletedAt)
|
||||
require.NoError(t, err)
|
||||
// create instance
|
||||
beforeCreate := time.Now()
|
||||
err := instanceRepo.Create(ctx, instance)
|
||||
assert.Equal(t, tt.err, err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
afterCreate := time.Now()
|
||||
|
||||
// check instance values
|
||||
instance, err = instanceRepo.Get(ctx,
|
||||
instanceRepo.NameCondition(database.TextOperationEqual, instance.Name),
|
||||
)
|
||||
assert.Equal(t, tt.instance.ID, instance.ID)
|
||||
assert.Equal(t, tt.instance.Name, instance.Name)
|
||||
assert.Equal(t, tt.instance.DefaultOrgID, instance.DefaultOrgID)
|
||||
assert.Equal(t, tt.instance.IAMProjectID, instance.IAMProjectID)
|
||||
assert.Equal(t, tt.instance.ConsoleClientID, instance.ConsoleClientID)
|
||||
assert.Equal(t, tt.instance.ConsoleAppID, instance.ConsoleAppID)
|
||||
assert.Equal(t, tt.instance.DefaultLanguage, instance.DefaultLanguage)
|
||||
assert.WithinRange(t, instance.CreatedAt, beforeCreate, afterCreate)
|
||||
assert.WithinRange(t, instance.UpdatedAt, beforeCreate, afterCreate)
|
||||
assert.Nil(t, instance.DeletedAt)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateNameInstance(t *testing.T) {
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
tests := []struct {
|
||||
name string
|
||||
testFunc func() *domain.Instance
|
||||
rowsAffected int64
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
testFunc: func() *domain.Instance {
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
|
||||
ctx := context.Background()
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientId: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
ctx := context.Background()
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
|
||||
// create instance
|
||||
err := instanceRepo.Create(ctx, &inst)
|
||||
assert.NoError(t, err)
|
||||
return &inst
|
||||
},
|
||||
rowsAffected: 1,
|
||||
},
|
||||
{
|
||||
name: "update non existent instance",
|
||||
testFunc: func() *domain.Instance {
|
||||
instanceId := gofakeit.Name()
|
||||
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
}
|
||||
return &inst
|
||||
},
|
||||
rowsAffected: 0,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
beforeUpdate := time.Now()
|
||||
|
||||
err := instanceRepo.Create(ctx, &inst)
|
||||
require.NoError(t, err)
|
||||
ctx := context.Background()
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
|
||||
_, err = instanceRepo.Get(ctx,
|
||||
instanceRepo.NameCondition(database.TextOperationEqual, instanceName),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
instance := tt.testFunc()
|
||||
|
||||
// update name
|
||||
err = instanceRepo.Update(ctx,
|
||||
instanceRepo.IDCondition(instanceId),
|
||||
instanceRepo.SetName("new_name"),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
// update name
|
||||
newName := "new_" + instance.Name
|
||||
rowsAffected, err := instanceRepo.Update(ctx,
|
||||
instanceRepo.IDCondition(instance.ID),
|
||||
instanceRepo.SetName(newName),
|
||||
)
|
||||
afterUpdate := time.Now()
|
||||
assert.NoError(t, err)
|
||||
|
||||
instance, err := instanceRepo.Get(ctx,
|
||||
instanceRepo.IDCondition(instanceId),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "new_name", instance.Name)
|
||||
assert.Equal(t, tt.rowsAffected, rowsAffected)
|
||||
|
||||
if rowsAffected == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// check instance values
|
||||
instance, err = instanceRepo.Get(ctx,
|
||||
instanceRepo.IDCondition(instance.ID),
|
||||
)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, newName, instance.Name)
|
||||
assert.WithinRange(t, instance.UpdatedAt, beforeUpdate, afterUpdate)
|
||||
assert.Nil(t, instance.DeletedAt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdeDeleteInstance(t *testing.T) {
|
||||
func TestGetInstance(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
testFunc func() *domain.Instance
|
||||
noInstanceReturned bool
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
testFunc: func() *domain.Instance {
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
|
||||
ctx := context.Background()
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
|
||||
// create instance
|
||||
err := instanceRepo.Create(ctx, &inst)
|
||||
assert.NoError(t, err)
|
||||
return &inst
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get non existent instance",
|
||||
testFunc: func() *domain.Instance {
|
||||
instanceId := gofakeit.Name()
|
||||
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
}
|
||||
return &inst
|
||||
},
|
||||
noInstanceReturned: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
|
||||
var instance *domain.Instance
|
||||
if tt.testFunc != nil {
|
||||
instance = tt.testFunc()
|
||||
}
|
||||
|
||||
// check instance values
|
||||
returnedInstance, err := instanceRepo.Get(ctx,
|
||||
instanceRepo.IDCondition(instance.ID),
|
||||
)
|
||||
assert.NoError(t, err)
|
||||
if tt.noInstanceReturned {
|
||||
assert.Nil(t, returnedInstance)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, returnedInstance.ID, instance.ID)
|
||||
assert.Equal(t, returnedInstance.Name, instance.Name)
|
||||
assert.Equal(t, returnedInstance.DefaultOrgID, instance.DefaultOrgID)
|
||||
assert.Equal(t, returnedInstance.IAMProjectID, instance.IAMProjectID)
|
||||
assert.Equal(t, returnedInstance.ConsoleClientID, instance.ConsoleClientID)
|
||||
assert.Equal(t, returnedInstance.ConsoleAppID, instance.ConsoleAppID)
|
||||
assert.Equal(t, returnedInstance.DefaultLanguage, instance.DefaultLanguage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListInstance(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
testFunc func() *domain.Instance
|
||||
|
||||
noInstanceReturned bool
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
testFunc: func() *domain.Instance {
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
|
||||
ctx := context.Background()
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
|
||||
// create instance
|
||||
err := instanceRepo.Create(ctx, &inst)
|
||||
assert.NoError(t, err)
|
||||
return &inst
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get non existent instance",
|
||||
testFunc: func() *domain.Instance {
|
||||
instanceId := gofakeit.Name()
|
||||
|
||||
inst := domain.Instance{
|
||||
ID: instanceId,
|
||||
}
|
||||
return &inst
|
||||
},
|
||||
noInstanceReturned: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
|
||||
var instance *domain.Instance
|
||||
if tt.testFunc != nil {
|
||||
instance = tt.testFunc()
|
||||
}
|
||||
|
||||
// check instance values
|
||||
returnedInstance, err := instanceRepo.List(ctx,
|
||||
instanceRepo.IDCondition(instance.ID),
|
||||
)
|
||||
assert.NoError(t, err)
|
||||
if tt.noInstanceReturned {
|
||||
assert.Nil(t, returnedInstance)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, returnedInstance.ID, instance.ID)
|
||||
assert.Equal(t, returnedInstance.Name, instance.Name)
|
||||
assert.Equal(t, returnedInstance.DefaultOrgID, instance.DefaultOrgID)
|
||||
assert.Equal(t, returnedInstance.IAMProjectID, instance.IAMProjectID)
|
||||
assert.Equal(t, returnedInstance.ConsoleClientID, instance.ConsoleClientID)
|
||||
assert.Equal(t, returnedInstance.ConsoleAppID, instance.ConsoleAppID)
|
||||
assert.Equal(t, returnedInstance.DefaultLanguage, instance.DefaultLanguage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateDeleteInstance(t *testing.T) {
|
||||
instanceRepo := repository.InstanceRepository(pool)
|
||||
instanceId := gofakeit.Name()
|
||||
instanceName := gofakeit.Name()
|
||||
@@ -100,29 +382,29 @@ func TestUpdeDeleteInstance(t *testing.T) {
|
||||
Name: instanceName,
|
||||
DefaultOrgID: "defaultOrgId",
|
||||
IAMProjectID: "iamProject",
|
||||
ConsoleClientId: "consoleCLient",
|
||||
ConsoleClientID: "consoleCLient",
|
||||
ConsoleAppID: "consoleApp",
|
||||
DefaultLanguage: "defaultLanguage",
|
||||
}
|
||||
|
||||
err := instanceRepo.Create(ctx, &inst)
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, err)
|
||||
|
||||
instance, err := instanceRepo.Get(ctx,
|
||||
instanceRepo.NameCondition(database.TextOperationEqual, instanceName),
|
||||
)
|
||||
require.NotNil(t, instance)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, instance)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// delete instance
|
||||
err = instanceRepo.Delete(ctx,
|
||||
instanceRepo.IDCondition(instanceId),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, err)
|
||||
|
||||
instance, err = instanceRepo.Get(ctx,
|
||||
instanceRepo.NameCondition(database.TextOperationEqual, instanceName),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, instance)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, instance)
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package repository
|
||||
import "github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
|
||||
type repository struct {
|
||||
// we can't reuse builder after it's been used already, I think we should remove it
|
||||
builder database.StatementBuilder
|
||||
client database.QueryExecutor
|
||||
}
|
||||
|
@@ -120,7 +120,8 @@ func (u *user) Create(ctx context.Context, user *domain.User) error {
|
||||
func (u *user) Delete(ctx context.Context, condition database.Condition) error {
|
||||
u.builder.WriteString("DELETE FROM users")
|
||||
u.writeCondition(condition)
|
||||
return u.client.Exec(ctx, u.builder.String(), u.builder.Args()...)
|
||||
_, err := u.client.Exec(ctx, u.builder.String(), u.builder.Args()...)
|
||||
return err
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
@@ -46,7 +46,8 @@ func (h userHuman) Update(ctx context.Context, condition database.Condition, cha
|
||||
|
||||
stmt := h.builder.String()
|
||||
|
||||
return h.client.Exec(ctx, stmt, h.builder.Args()...)
|
||||
_, err := h.client.Exec(ctx, stmt, h.builder.Args()...)
|
||||
return err
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
@@ -18,13 +18,14 @@ var _ domain.MachineRepository = (*userMachine)(nil)
|
||||
// -------------------------------------------------------------
|
||||
|
||||
// Update implements [domain.MachineRepository].
|
||||
func (m userMachine) Update(ctx context.Context, condition database.Condition, changes ...database.Change) (err error) {
|
||||
func (m userMachine) Update(ctx context.Context, condition database.Condition, changes ...database.Change) error {
|
||||
m.builder.WriteString("UPDATE user_machines SET ")
|
||||
database.Changes(changes).Write(&m.builder)
|
||||
m.writeCondition(condition)
|
||||
m.writeReturning()
|
||||
|
||||
return m.client.Exec(ctx, m.builder.String(), m.builder.Args()...)
|
||||
_, err := m.client.Exec(ctx, m.builder.String(), m.builder.Args()...)
|
||||
return err
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
@@ -15,7 +15,8 @@ type Event struct {
|
||||
|
||||
func Publish(ctx context.Context, events []*Event, db database.Executor) error {
|
||||
for _, event := range events {
|
||||
if err := db.Exec(ctx, `INSERT INTO events (aggregate_type, aggregate_id) VALUES ($1, $2)`, event.AggregateType, event.AggregateID); err != nil {
|
||||
_, err := db.Exec(ctx, `INSERT INTO events (aggregate_type, aggregate_id) VALUES ($1, $2)`, event.AggregateType, event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
4
go.mod
4
go.mod
@@ -43,6 +43,7 @@ require (
|
||||
github.com/h2non/gock v1.2.0
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/improbable-eng/grpc-web v0.15.0
|
||||
github.com/jackc/pgconn v1.14.3
|
||||
github.com/jackc/pgx/v5 v5.7.3
|
||||
github.com/jackc/tern/v2 v2.3.3
|
||||
github.com/jarcoal/jpath v0.0.0-20140328210829-f76b8b2dbf52
|
||||
@@ -135,6 +136,9 @@ require (
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
|
9
go.sum
9
go.sum
@@ -449,10 +449,19 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
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 v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
|
||||
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
|
||||
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw=
|
||||
github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
|
||||
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/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.3 h1:PO1wNKj/bTAwxSJnO1Z4Ai8j4magtqg2SLNjEDzcXQo=
|
||||
|
Reference in New Issue
Block a user