mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 18:07:31 +00:00
feat: init migrations for transactional tables (#9946)
# Which Problems Are Solved To start with transactional tables we need to setup the new `zitadel` schema in a way that does not rely on the event store later. # How the Problems Are Solved Setup step added which calls the function which executes the migrations. # Additional Changes none # Additional Context - closes #9933
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
// These tests give an overview of how to use the domain package.
|
||||
func TestExample(t *testing.T) {
|
||||
t.Skip("skip example test because it is not a real test")
|
||||
ctx := context.Background()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
@@ -19,6 +19,7 @@ var (
|
||||
|
||||
type Config struct {
|
||||
*pgxpool.Config
|
||||
*pgxpool.Pool
|
||||
|
||||
// Host string
|
||||
// Port int32
|
||||
@@ -37,7 +38,7 @@ type Config struct {
|
||||
|
||||
// Connect implements [database.Connector].
|
||||
func (c *Config) Connect(ctx context.Context) (database.Pool, error) {
|
||||
pool, err := pgxpool.NewWithConfig(ctx, c.Config)
|
||||
pool, err := c.getPool(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -47,6 +48,13 @@ func (c *Config) Connect(ctx context.Context) (database.Pool, error) {
|
||||
return &pgxPool{pool}, nil
|
||||
}
|
||||
|
||||
func (c *Config) getPool(ctx context.Context) (*pgxpool.Pool, error) {
|
||||
if c.Pool != nil {
|
||||
return c.Pool, nil
|
||||
}
|
||||
return pgxpool.NewWithConfig(ctx, c.Config)
|
||||
}
|
||||
|
||||
func NameMatcher(name string) bool {
|
||||
return slices.Contains([]string{"postgres", "pg"}, strings.ToLower(name))
|
||||
}
|
||||
|
@@ -6,11 +6,15 @@ import (
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres/migration"
|
||||
)
|
||||
|
||||
type pgxConn struct{ *pgxpool.Conn }
|
||||
|
||||
var _ database.Client = (*pgxConn)(nil)
|
||||
var (
|
||||
_ database.Client = (*pgxConn)(nil)
|
||||
_ database.Migrator = (*pgxConn)(nil)
|
||||
)
|
||||
|
||||
// Release implements [database.Client].
|
||||
func (c *pgxConn) Release(_ context.Context) error {
|
||||
@@ -46,3 +50,8 @@ func (c *pgxConn) Exec(ctx context.Context, sql string, args ...any) error {
|
||||
_, err := c.Conn.Exec(ctx, sql, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
// Migrate implements [database.Migrator].
|
||||
func (c *pgxConn) Migrate(ctx context.Context) error {
|
||||
return migration.Migrate(ctx, c.Conn.Conn())
|
||||
}
|
||||
|
@@ -0,0 +1,16 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed 001_instance_table/up.sql
|
||||
up001InstanceTable string
|
||||
//go:embed 001_instance_table/down.sql
|
||||
down001InstanceTable string
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerSQLMigration(1, up001InstanceTable, down001InstanceTable)
|
||||
}
|
@@ -0,0 +1 @@
|
||||
DROP TABLE zitadel.instances;
|
@@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS zitadel.instances(
|
||||
id VARCHAR(100) NOT NULL
|
||||
, PRIMARY KEY (id)
|
||||
|
||||
, name VARCHAR(100) NOT NULL
|
||||
);
|
@@ -0,0 +1,13 @@
|
||||
// This package contains the migration logic for the PostgreSQL dialect.
|
||||
// It uses the [github.com/jackc/tern/v2/migrate] package to handle the migration process.
|
||||
//
|
||||
// **Developer Note**:
|
||||
//
|
||||
// Each migration MUST be registered in an init function.
|
||||
// Create a go file for each migration with the sequence of the migration as prefix and some descriptive name.
|
||||
// The file name MUST be in the format <sequence>_<name>.go.
|
||||
// Each migration SHOULD provide an up and down migration.
|
||||
// Prefer to write SQL statements instead of funcs if it is reasonable.
|
||||
// To keep the folder clean create a folder to store the sql files with the following format: <sequence>_<name>/{up/down}.sql.
|
||||
// And use the go embed directive to embed the sql files.
|
||||
package migration
|
@@ -0,0 +1,33 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/tern/v2/migrate"
|
||||
)
|
||||
|
||||
var migrations []*migrate.Migration
|
||||
|
||||
func Migrate(ctx context.Context, conn *pgx.Conn) error {
|
||||
// we need to ensure that the schema exists before we can run the migration
|
||||
// because creating the migrations table already required the schema
|
||||
_, err := conn.Exec(ctx, "CREATE SCHEMA IF NOT EXISTS zitadel")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
migrator, err := migrate.NewMigrator(ctx, conn, "zitadel.migrations")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
migrator.Migrations = migrations
|
||||
return migrator.Migrate(ctx)
|
||||
}
|
||||
|
||||
func registerSQLMigration(sequence int32, up, down string) {
|
||||
migrations = append(migrations, &migrate.Migration{
|
||||
Sequence: sequence,
|
||||
UpSQL: up,
|
||||
DownSQL: down,
|
||||
})
|
||||
}
|
@@ -6,11 +6,15 @@ import (
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres/migration"
|
||||
)
|
||||
|
||||
type pgxPool struct{ *pgxpool.Pool }
|
||||
|
||||
var _ database.Pool = (*pgxPool)(nil)
|
||||
var (
|
||||
_ database.Pool = (*pgxPool)(nil)
|
||||
_ database.Migrator = (*pgxPool)(nil)
|
||||
)
|
||||
|
||||
// Acquire implements [database.Pool].
|
||||
func (c *pgxPool) Acquire(ctx context.Context) (database.Client, error) {
|
||||
@@ -55,3 +59,12 @@ func (c *pgxPool) Close(_ context.Context) error {
|
||||
c.Pool.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Migrate implements [database.Migrator].
|
||||
func (c *pgxPool) Migrate(ctx context.Context) error {
|
||||
client, err := c.Pool.Acquire(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return migration.Migrate(ctx, client.Conn())
|
||||
}
|
||||
|
8
backend/v3/storage/database/migration.go
Normal file
8
backend/v3/storage/database/migration.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package database
|
||||
|
||||
import "context"
|
||||
|
||||
type Migrator interface {
|
||||
// Migrate executes migrations to setup the database.
|
||||
Migrate(ctx context.Context) error
|
||||
}
|
@@ -12,6 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestQueryUser(t *testing.T) {
|
||||
t.Skip("tests are meant as examples and are not real tests")
|
||||
t.Run("User filters", func(t *testing.T) {
|
||||
client := dbmock.NewMockClient(gomock.NewController(t))
|
||||
|
||||
@@ -67,6 +68,7 @@ func TestArg(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWriteUser(t *testing.T) {
|
||||
t.Skip("tests are meant as examples and are not real tests")
|
||||
t.Run("update user", func(t *testing.T) {
|
||||
user := repository.UserRepository(nil)
|
||||
user.Human().Update(context.Background(), user.IDCondition("test"), user.SetUsername("test"))
|
||||
|
Reference in New Issue
Block a user