Skip to content

Commit 0d43679

Browse files
committed
fix: db reset should apply initial schema before service restart
1 parent af77b82 commit 0d43679

File tree

2 files changed

+33
-78
lines changed

2 files changed

+33
-78
lines changed

internal/db/reset/reset.go

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,25 @@ func resetDatabase(ctx context.Context, fsys afero.Fs, options ...func(*pgx.Conn
6464
if err := RecreateDatabase(ctx, options...); err != nil {
6565
return err
6666
}
67-
defer RestartDatabase(context.Background(), os.Stderr)
68-
return initDatabase(ctx, fsys, options...)
69-
}
70-
71-
func initDatabase(ctx context.Context, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
72-
url := fmt.Sprintf("postgresql://supabase_admin:postgres@localhost:%d/postgres?connect_timeout=2", utils.Config.Db.Port)
73-
conn, err := utils.ConnectByUrl(ctx, url, options...)
74-
if err != nil {
67+
if err := initDatabase(ctx, options...); err != nil {
7568
return err
7669
}
77-
defer conn.Close(context.Background())
78-
fmt.Fprintln(os.Stderr, "Initializing schema...")
79-
if err := apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.InitialSchemaSql)); err != nil {
70+
RestartDatabase(context.Background(), os.Stderr)
71+
conn, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{}, options...)
72+
if err != nil {
8073
return err
8174
}
82-
if _, err := conn.Exec(ctx, SET_POSTGRES_ROLE); err != nil {
75+
defer conn.Close(context.Background())
76+
return InitialiseDatabase(ctx, conn, fsys)
77+
}
78+
79+
func initDatabase(ctx context.Context, options ...func(*pgx.ConnConfig)) error {
80+
conn, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{User: "supabase_admin"}, options...)
81+
if err != nil {
8382
return err
8483
}
85-
return InitialiseDatabase(ctx, conn, fsys)
84+
defer conn.Close(context.Background())
85+
return apply.BatchExecDDL(ctx, conn, strings.NewReader(utils.InitialSchemaSql))
8686
}
8787

8888
func InitialiseDatabase(ctx context.Context, conn *pgx.Conn, fsys afero.Fs) error {
@@ -94,21 +94,22 @@ func InitialiseDatabase(ctx context.Context, conn *pgx.Conn, fsys afero.Fs) erro
9494

9595
// Recreate postgres database by connecting to template1
9696
func RecreateDatabase(ctx context.Context, options ...func(*pgx.ConnConfig)) error {
97-
url := fmt.Sprintf("postgresql://supabase_admin:postgres@localhost:%d/template1?connect_timeout=2", utils.Config.Db.Port)
98-
conn, err := utils.ConnectByUrl(ctx, url, options...)
97+
conn, err := utils.ConnectLocalPostgres(ctx, pgconn.Config{User: "supabase_admin", Database: "template1"}, options...)
9998
if err != nil {
10099
return err
101100
}
102101
defer conn.Close(context.Background())
103102
if err := DisconnectClients(ctx, conn); err != nil {
104103
return err
105104
}
106-
drop := "DROP DATABASE IF EXISTS postgres WITH (FORCE);"
107-
if _, err := conn.Exec(ctx, drop); err != nil {
108-
return err
105+
// We are not dropping roles here because they are cluster level entities. Use stop && start instead.
106+
sql := repair.MigrationFile{
107+
Lines: []string{
108+
"DROP DATABASE IF EXISTS postgres WITH (FORCE)",
109+
"CREATE DATABASE postgres WITH OWNER postgres",
110+
},
109111
}
110-
_, err = conn.Exec(ctx, "CREATE DATABASE postgres WITH OWNER postgres;")
111-
return err
112+
return sql.ExecBatch(ctx, conn)
112113
}
113114

114115
func SeedDatabase(ctx context.Context, conn *pgx.Conn, fsys afero.Fs) error {
@@ -133,10 +134,8 @@ func DisconnectClients(ctx context.Context, conn *pgx.Conn) error {
133134
}
134135
}
135136
term := fmt.Sprintf(utils.TerminateDbSqlFmt, "postgres")
136-
if _, err := conn.Exec(ctx, term); err != nil {
137-
return err
138-
}
139-
return nil
137+
_, err := conn.Exec(ctx, term)
138+
return err
140139
}
141140

142141
func RestartDatabase(ctx context.Context, w io.Writer) {
@@ -229,7 +228,7 @@ func ListSchemas(ctx context.Context, conn *pgx.Conn, exclude ...string) ([]stri
229228
}
230229
schemas = append(schemas, name)
231230
}
232-
return schemas, nil
231+
return schemas, rows.Err()
233232
}
234233

235234
func likeEscapeSchema(schemas []string) (result []string) {

internal/db/reset/reset_test.go

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -75,81 +75,36 @@ func TestInitDatabase(t *testing.T) {
7575
t.Run("initialises postgres database", func(t *testing.T) {
7676
utils.Config.Db.Port = 54322
7777
utils.InitialSchemaSql = "CREATE SCHEMA public"
78-
// Setup in-memory fs
79-
fsys := afero.NewMemMapFs()
8078
// Setup mock postgres
8179
conn := pgtest.NewConn()
8280
defer conn.Close(t)
8381
conn.Query(utils.InitialSchemaSql).
84-
Reply("CREATE SCHEMA").
85-
Query(SET_POSTGRES_ROLE).
86-
Reply("SET ROLE")
82+
Reply("CREATE SCHEMA")
8783
// Run test
88-
assert.NoError(t, initDatabase(context.Background(), fsys, conn.Intercept))
84+
assert.NoError(t, initDatabase(context.Background(), conn.Intercept))
8985
})
9086

9187
t.Run("throws error on connect failure", func(t *testing.T) {
9288
utils.Config.Db.Port = 0
93-
// Setup in-memory fs
94-
fsys := afero.NewMemMapFs()
9589
// Run test
96-
err := initDatabase(context.Background(), fsys)
90+
err := initDatabase(context.Background())
9791
// Check error
9892
assert.ErrorContains(t, err, "invalid port (outside range)")
9993
})
10094

10195
t.Run("throws error on duplicate schema", func(t *testing.T) {
10296
utils.Config.Db.Port = 54322
10397
utils.InitialSchemaSql = "CREATE SCHEMA public"
104-
// Setup in-memory fs
105-
fsys := afero.NewMemMapFs()
10698
// Setup mock postgres
10799
conn := pgtest.NewConn()
108100
defer conn.Close(t)
109101
conn.Query(utils.InitialSchemaSql).
110102
ReplyError(pgerrcode.DuplicateSchema, `schema "public" already exists`)
111103
// Run test
112-
err := initDatabase(context.Background(), fsys, conn.Intercept)
104+
err := initDatabase(context.Background(), conn.Intercept)
113105
// Check error
114106
assert.ErrorContains(t, err, `ERROR: schema "public" already exists (SQLSTATE 42P06)`)
115107
})
116-
117-
t.Run("throws error on failure to switch role", func(t *testing.T) {
118-
utils.Config.Db.Port = 54322
119-
utils.InitialSchemaSql = "CREATE SCHEMA public"
120-
// Setup in-memory fs
121-
fsys := afero.NewMemMapFs()
122-
// Setup mock postgres
123-
conn := pgtest.NewConn()
124-
defer conn.Close(t)
125-
conn.Query(utils.InitialSchemaSql).
126-
Reply("CREATE SCHEMA").
127-
Query(SET_POSTGRES_ROLE).
128-
Reply("SET ROLE").
129-
ReplyError(pgerrcode.InvalidParameterValue, `role "test" does not exist`)
130-
// Run test
131-
err := initDatabase(context.Background(), fsys, conn.Intercept)
132-
// Check error
133-
assert.ErrorContains(t, err, `ERROR: role "test" does not exist (SQLSTATE 22023)`)
134-
})
135-
136-
t.Run("throws error on migration failure", func(t *testing.T) {
137-
utils.Config.Db.Port = 54322
138-
utils.InitialSchemaSql = "CREATE SCHEMA public"
139-
// Setup in-memory fs
140-
fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
141-
// Setup mock postgres
142-
conn := pgtest.NewConn()
143-
defer conn.Close(t)
144-
conn.Query(utils.InitialSchemaSql).
145-
Reply("CREATE SCHEMA").
146-
Query(SET_POSTGRES_ROLE).
147-
Reply("SET ROLE")
148-
// Run test
149-
err := initDatabase(context.Background(), fsys, conn.Intercept)
150-
// Check error
151-
assert.ErrorIs(t, err, os.ErrPermission)
152-
})
153108
}
154109

155110
func TestSeedDatabase(t *testing.T) {
@@ -219,9 +174,9 @@ func TestRecreateDatabase(t *testing.T) {
219174
Reply("ALTER DATABASE").
220175
Query(fmt.Sprintf(utils.TerminateDbSqlFmt, "postgres")).
221176
Reply("DO").
222-
Query("DROP DATABASE IF EXISTS postgres WITH (FORCE);").
177+
Query("DROP DATABASE IF EXISTS postgres WITH (FORCE)").
223178
Reply("DROP DATABASE").
224-
Query("CREATE DATABASE postgres WITH OWNER postgres;").
179+
Query("CREATE DATABASE postgres WITH OWNER postgres").
225180
Reply("CREATE DATABASE")
226181
// Run test
227182
assert.NoError(t, RecreateDatabase(context.Background(), conn.Intercept))
@@ -269,8 +224,9 @@ func TestRecreateDatabase(t *testing.T) {
269224
Reply("ALTER DATABASE").
270225
Query(fmt.Sprintf(utils.TerminateDbSqlFmt, "postgres")).
271226
Reply("DO").
272-
Query("DROP DATABASE IF EXISTS postgres WITH (FORCE);").
273-
ReplyError(pgerrcode.ObjectInUse, `database "postgres" is used by an active logical replication slot`)
227+
Query("DROP DATABASE IF EXISTS postgres WITH (FORCE)").
228+
ReplyError(pgerrcode.ObjectInUse, `database "postgres" is used by an active logical replication slot`).
229+
Query("CREATE DATABASE postgres WITH OWNER postgres")
274230
// Run test
275231
err := RecreateDatabase(context.Background(), conn.Intercept)
276232
// Check error

0 commit comments

Comments
 (0)