Skip to content

Commit 4f05d06

Browse files
committed
psql working
1 parent d043ece commit 4f05d06

File tree

5 files changed

+181
-64
lines changed

5 files changed

+181
-64
lines changed

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ module github.com/cprosche/mig
33
go 1.23.2
44

55
require (
6+
github.com/lib/pq v1.10.9
67
github.com/mattn/go-sqlite3 v1.14.24
78
github.com/stretchr/testify v1.10.0
89
)
910

1011
require (
1112
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/kr/pretty v0.3.0 // indirect
1214
github.com/pmezard/go-difflib v1.0.0 // indirect
15+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
1316
gopkg.in/yaml.v3 v3.0.1 // indirect
1417
)

go.sum

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
1+
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
12
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
23
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
5+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
6+
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
7+
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
8+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
9+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
10+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
11+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
12+
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
13+
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
314
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
415
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
516
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
617
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
18+
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
19+
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
720
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
821
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
9-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1022
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
23+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
24+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
25+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
26+
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
1127
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
1228
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

mig.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type Mig struct {
3535

3636
var migrationTableSchema = `
3737
CREATE TABLE IF NOT EXISTS migrations (
38-
id INTEGER PRIMARY KEY,
38+
id SERIAL PRIMARY KEY,
3939
filename TEXT,
4040
raw TEXT,
4141
hash TEXT,
@@ -72,10 +72,12 @@ func New(c Config) (*Mig, error) {
7272
}
7373

7474
// Create migrations table if it doesn't exist
75-
m.config.Db.Exec(migrationTableSchema)
75+
_, err := m.config.Db.Exec(migrationTableSchema)
76+
if err != nil {
77+
return &Mig{}, fmt.Errorf("mig: error creating migrations table: %w", err)
78+
}
7679

7780
// Get migrations from filesystem or from the provided slice
78-
var err error
7981
if m.config.Fs != nil {
8082
m.config.Migrations, err = m.getMigrationsFromFS()
8183
if err != nil {
@@ -137,7 +139,11 @@ func (mig *Mig) runUp() error {
137139
return err
138140
}
139141

140-
_, err = mig.config.Db.Exec("INSERT INTO migrations (id, filename, raw, hash, up, down) VALUES (?, ?, ?, ?, ?, ?)",
142+
_, err = mig.config.Db.Exec(`
143+
INSERT INTO
144+
migrations (id, filename, raw, hash, up, down)
145+
VALUES
146+
($1, $2, $3, $4, $5, $6)`,
141147
m.Id, m.FileName, m.raw, m.hash, m.Up, m.Down)
142148
if err != nil {
143149
return err
@@ -194,7 +200,7 @@ func (mig *Mig) runDownTo(endId int) error {
194200
}
195201

196202
// remove migration from migrations table
197-
_, err = mig.config.Db.Exec("DELETE FROM migrations WHERE id = ?", dbMigrations[i].Id)
203+
_, err = mig.config.Db.Exec("DELETE FROM migrations WHERE id = $1", dbMigrations[i].Id)
198204
if err != nil {
199205
return fmt.Errorf("error deleting migration from migrations table: %w", err)
200206
}

psql_test.go

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,95 @@
11
package mig
22

3-
// TODO: add tests for psql
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"log"
7+
"os"
8+
"os/exec"
9+
"testing"
10+
"time"
11+
12+
_ "github.com/lib/pq"
13+
"github.com/stretchr/testify/assert"
14+
)
15+
16+
func TestPostgres(t *testing.T) {
17+
t.Run("FS migrate runs successfully", func(t *testing.T) {
18+
err := startPostgresContainer()
19+
assert.NoError(t, err)
20+
defer stopPostgresContainer()
21+
22+
db, err := getPostgresConnection()
23+
assert.NoError(t, err)
24+
defer db.Close()
25+
26+
m, err := New(Config{
27+
Db: db,
28+
Fs: os.DirFS("./test/migrations1"),
29+
})
30+
if err != nil {
31+
t.Fatalf("failed to create mig: %v", err)
32+
}
33+
34+
err = m.Migrate()
35+
assert.NoError(t, err)
36+
37+
tableMustExistPostgres(t, db, "migrations")
38+
tableMustExistPostgres(t, db, "test_table_1")
39+
tableMustExistPostgres(t, db, "test_table_2")
40+
tableMustExistPostgres(t, db, "test_table_3")
41+
tableMustNotExistPostgres(t, db, "test_table_4")
42+
})
43+
}
44+
45+
func startPostgresContainer() error {
46+
cmd := exec.Command("docker", "run", "-d", "--name", "pg", "-p", "5432:5432", "-e", "POSTGRES_PASSWORD=secret", "postgres")
47+
output, err := cmd.CombinedOutput()
48+
if err != nil {
49+
return fmt.Errorf("failed to start postgres container: %v, output: %s", err, string(output))
50+
}
51+
return nil
52+
}
53+
54+
func stopPostgresContainer() {
55+
cmd := exec.Command("docker", "stop", "pg")
56+
if err := cmd.Run(); err != nil {
57+
log.Printf("failed to stop postgres container: %v", err)
58+
}
59+
cmd = exec.Command("docker", "rm", "-f", "pg")
60+
if err := cmd.Run(); err != nil {
61+
log.Printf("failed to remove postgres container: %v", err)
62+
}
63+
}
64+
65+
func getPostgresConnection() (*sql.DB, error) {
66+
connStr := "user=postgres password=secret dbname=postgres sslmode=disable host=localhost port=5432"
67+
db, err := sql.Open("postgres", connStr)
68+
if err != nil {
69+
return nil, fmt.Errorf("failed to open connection: %v", err)
70+
}
71+
72+
for i := 0; i < 10; i++ {
73+
err = db.Ping()
74+
if err == nil {
75+
return db, nil
76+
}
77+
time.Sleep(1 * time.Second)
78+
}
79+
80+
return nil, fmt.Errorf("failed to connect to postgres: %v", err)
81+
}
82+
83+
func tableMustExistPostgres(t *testing.T, db *sql.DB, tableName string) {
84+
rows, err := db.Query("SELECT table_name FROM information_schema.tables WHERE table_name = $1;", tableName)
85+
assert.NoError(t, err)
86+
defer rows.Close()
87+
assert.True(t, rows.Next(), "table %s must exist", tableName)
88+
}
89+
90+
func tableMustNotExistPostgres(t *testing.T, db *sql.DB, tableName string) {
91+
rows, err := db.Query("SELECT table_name FROM information_schema.tables WHERE table_name = $1;", tableName)
92+
assert.NoError(t, err)
93+
defer rows.Close()
94+
assert.False(t, rows.Next(), "table %s must not exist", tableName)
95+
}

sqlite_test.go

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ func TestMigrate(t *testing.T) {
3838
err = m.Migrate()
3939
assert.Nil(t, err)
4040

41-
tableMustExist(t, db, "migrations")
42-
tableMustExist(t, db, "test1")
43-
tableMustExist(t, db, "test2")
44-
tableMustNotExist(t, db, "test3")
41+
tableMustExistSqlite(t, db, "migrations")
42+
tableMustExistSqlite(t, db, "test1")
43+
tableMustExistSqlite(t, db, "test2")
44+
tableMustNotExistSqlite(t, db, "test3")
4545

4646
os.Remove(testDbPath)
4747
})
@@ -74,16 +74,16 @@ func TestMigrate(t *testing.T) {
7474
err = m.Migrate()
7575
assert.Nil(t, err)
7676

77-
tableMustExist(t, db, "migrations")
78-
tableMustExist(t, db, "test1")
79-
tableMustExist(t, db, "test2")
77+
tableMustExistSqlite(t, db, "migrations")
78+
tableMustExistSqlite(t, db, "test1")
79+
tableMustExistSqlite(t, db, "test2")
8080

8181
err = m.Migrate()
8282
assert.Nil(t, err)
8383

84-
tableMustExist(t, db, "migrations")
85-
tableMustExist(t, db, "test1")
86-
tableMustExist(t, db, "test2")
84+
tableMustExistSqlite(t, db, "migrations")
85+
tableMustExistSqlite(t, db, "test1")
86+
tableMustExistSqlite(t, db, "test2")
8787

8888
os.Remove(testDbPath)
8989
})
@@ -116,10 +116,10 @@ func TestMigrate(t *testing.T) {
116116
err = m.Migrate()
117117
assert.Nil(t, err)
118118

119-
tableMustExist(t, db, "migrations")
120-
tableMustExist(t, db, "test1")
121-
tableMustExist(t, db, "test2")
122-
tableMustNotExist(t, db, "test3")
119+
tableMustExistSqlite(t, db, "migrations")
120+
tableMustExistSqlite(t, db, "test1")
121+
tableMustExistSqlite(t, db, "test2")
122+
tableMustNotExistSqlite(t, db, "test3")
123123

124124
m.config.Migrations = append(m.config.Migrations, Migration{
125125
Id: 3,
@@ -130,10 +130,10 @@ func TestMigrate(t *testing.T) {
130130
err = m.Migrate()
131131
assert.Nil(t, err)
132132

133-
tableMustExist(t, db, "migrations")
134-
tableMustExist(t, db, "test1")
135-
tableMustExist(t, db, "test2")
136-
tableMustExist(t, db, "test3")
133+
tableMustExistSqlite(t, db, "migrations")
134+
tableMustExistSqlite(t, db, "test1")
135+
tableMustExistSqlite(t, db, "test2")
136+
tableMustExistSqlite(t, db, "test3")
137137

138138
os.Remove(testDbPath)
139139
})
@@ -171,20 +171,20 @@ func TestMigrate(t *testing.T) {
171171
err = m.Migrate()
172172
assert.Nil(t, err)
173173

174-
tableMustExist(t, db, "migrations")
175-
tableMustExist(t, db, "test1")
176-
tableMustExist(t, db, "test2")
177-
tableMustExist(t, db, "test3")
174+
tableMustExistSqlite(t, db, "migrations")
175+
tableMustExistSqlite(t, db, "test1")
176+
tableMustExistSqlite(t, db, "test2")
177+
tableMustExistSqlite(t, db, "test3")
178178

179179
m.config.Migrations = m.config.Migrations[:2]
180180

181181
err = m.Migrate()
182182
assert.Nil(t, err)
183183

184-
tableMustExist(t, db, "migrations")
185-
tableMustExist(t, db, "test1")
186-
tableMustExist(t, db, "test2")
187-
tableMustNotExist(t, db, "test3")
184+
tableMustExistSqlite(t, db, "migrations")
185+
tableMustExistSqlite(t, db, "test1")
186+
tableMustExistSqlite(t, db, "test2")
187+
tableMustNotExistSqlite(t, db, "test3")
188188

189189
os.Remove(testDbPath)
190190
})
@@ -222,36 +222,36 @@ func TestMigrate(t *testing.T) {
222222
err = m.Migrate()
223223
assert.Nil(t, err)
224224

225-
tableMustExist(t, db, "migrations")
226-
tableMustExist(t, db, "test1")
227-
tableMustExist(t, db, "test2")
228-
tableMustExist(t, db, "test3")
229-
tableMustNotExist(t, db, "test4")
225+
tableMustExistSqlite(t, db, "migrations")
226+
tableMustExistSqlite(t, db, "test1")
227+
tableMustExistSqlite(t, db, "test2")
228+
tableMustExistSqlite(t, db, "test3")
229+
tableMustNotExistSqlite(t, db, "test4")
230230

231231
m.config.Migrations[1].Up = "CREATE TABLE test4 (id INTEGER PRIMARY KEY, name TEXT, age INTEGER);"
232232
m.config.Migrations[1].Down = "DROP TABLE test4;"
233233

234234
err = m.Migrate()
235235
assert.Nil(t, err)
236236

237-
tableMustExist(t, db, "migrations")
238-
tableMustExist(t, db, "test1")
239-
tableMustNotExist(t, db, "test2")
240-
tableMustExist(t, db, "test3")
241-
tableMustExist(t, db, "test4")
237+
tableMustExistSqlite(t, db, "migrations")
238+
tableMustExistSqlite(t, db, "test1")
239+
tableMustNotExistSqlite(t, db, "test2")
240+
tableMustExistSqlite(t, db, "test3")
241+
tableMustExistSqlite(t, db, "test4")
242242

243243
m.config.Migrations[0].Up = "CREATE TABLE test5 (id INTEGER PRIMARY KEY, name TEXT);"
244244
m.config.Migrations[0].Down = "DROP TABLE test5;"
245245

246246
err = m.Migrate()
247247
assert.Nil(t, err)
248248

249-
tableMustExist(t, db, "migrations")
250-
tableMustNotExist(t, db, "test1")
251-
tableMustNotExist(t, db, "test2")
252-
tableMustExist(t, db, "test3")
253-
tableMustExist(t, db, "test4")
254-
tableMustExist(t, db, "test5")
249+
tableMustExistSqlite(t, db, "migrations")
250+
tableMustNotExistSqlite(t, db, "test1")
251+
tableMustNotExistSqlite(t, db, "test2")
252+
tableMustExistSqlite(t, db, "test3")
253+
tableMustExistSqlite(t, db, "test4")
254+
tableMustExistSqlite(t, db, "test5")
255255

256256
os.Remove(testDbPath)
257257
})
@@ -271,37 +271,37 @@ func TestMigrate(t *testing.T) {
271271
err = m.Migrate()
272272
assert.Nil(t, err)
273273

274-
tableMustExist(t, db, "migrations")
275-
tableMustExist(t, db, "test_table_1")
276-
tableMustExist(t, db, "test_table_2")
277-
tableMustExist(t, db, "test_table_3")
278-
tableMustNotExist(t, db, "test_table_4")
274+
tableMustExistSqlite(t, db, "migrations")
275+
tableMustExistSqlite(t, db, "test_table_1")
276+
tableMustExistSqlite(t, db, "test_table_2")
277+
tableMustExistSqlite(t, db, "test_table_3")
278+
tableMustNotExistSqlite(t, db, "test_table_4")
279279

280280
m.config.Migrations[2].Up = "CREATE TABLE test_table_5 (id INTEGER PRIMARY KEY, name TEXT);"
281281
m.config.Migrations[2].Down = "DROP TABLE test_table_5;"
282282
err = m.Migrate()
283283
assert.Nil(t, err)
284284

285-
tableMustExist(t, db, "migrations")
286-
tableMustExist(t, db, "test_table_1")
287-
tableMustExist(t, db, "test_table_2")
288-
tableMustNotExist(t, db, "test_table_3")
289-
tableMustNotExist(t, db, "test_table_4")
290-
tableMustExist(t, db, "test_table_5")
285+
tableMustExistSqlite(t, db, "migrations")
286+
tableMustExistSqlite(t, db, "test_table_1")
287+
tableMustExistSqlite(t, db, "test_table_2")
288+
tableMustNotExistSqlite(t, db, "test_table_3")
289+
tableMustNotExistSqlite(t, db, "test_table_4")
290+
tableMustExistSqlite(t, db, "test_table_5")
291291

292292
os.Remove(testDbPath)
293293
})
294294
}
295295

296-
func tableMustExist(t *testing.T, db *sql.DB, tableName string) {
297-
rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name=?;", tableName)
296+
func tableMustExistSqlite(t *testing.T, db *sql.DB, tableName string) {
297+
rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name=$1;", tableName)
298298
assert.Nil(t, err)
299299
defer rows.Close()
300300
assert.True(t, rows.Next(), "table %s must exist", tableName)
301301
}
302302

303-
func tableMustNotExist(t *testing.T, db *sql.DB, tableName string) {
304-
rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name=?;", tableName)
303+
func tableMustNotExistSqlite(t *testing.T, db *sql.DB, tableName string) {
304+
rows, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name=$1;", tableName)
305305
assert.Nil(t, err)
306306
defer rows.Close()
307307
assert.False(t, rows.Next(), "table %s must not exist", tableName)

0 commit comments

Comments
 (0)