@@ -3,23 +3,31 @@ package local
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "hash/fnv"
6
7
"net/url"
7
8
"os"
8
9
"strings"
9
- "sync"
10
10
"testing"
11
11
12
12
"github.com/jackc/pgx/v5"
13
- "github.com/jackc/pgx/v5/pgxpool "
13
+ "golang.org/x/sync/singleflight "
14
14
15
15
migrate "github.com/sqlc-dev/sqlc/internal/migrations"
16
+ "github.com/sqlc-dev/sqlc/internal/pgx/poolcache"
16
17
"github.com/sqlc-dev/sqlc/internal/sql/sqlpath"
17
18
)
18
19
19
- var postgresPool * pgxpool.Pool
20
- var postgresSync sync.Once
20
+ var flight singleflight.Group
21
21
22
22
func PostgreSQL (t * testing.T , migrations []string ) string {
23
+ return postgreSQL (t , migrations , true )
24
+ }
25
+
26
+ func ReadOnlyPostgreSQL (t * testing.T , migrations []string ) string {
27
+ return postgreSQL (t , migrations , false )
28
+ }
29
+
30
+ func postgreSQL (t * testing.T , migrations []string , rw bool ) string {
23
31
ctx := context .Background ()
24
32
t .Helper ()
25
33
@@ -28,65 +36,83 @@ func PostgreSQL(t *testing.T, migrations []string) string {
28
36
t .Skip ("POSTGRESQL_SERVER_URI is empty" )
29
37
}
30
38
31
- postgresSync .Do (func () {
32
- pool , err := pgxpool .New (ctx , dburi )
33
- if err != nil {
34
- t .Fatal (err )
35
- }
36
- postgresPool = pool
37
- })
38
-
39
- if postgresPool == nil {
40
- t .Fatalf ("PostgreSQL pool creation failed" )
39
+ postgresPool , err := poolcache .New (ctx , dburi )
40
+ if err != nil {
41
+ t .Fatalf ("PostgreSQL pool creation failed: %s" , err )
41
42
}
42
43
43
44
var seed []string
44
45
files , err := sqlpath .Glob (migrations )
45
46
if err != nil {
46
47
t .Fatal (err )
47
48
}
49
+
50
+ h := fnv .New64 ()
48
51
for _ , f := range files {
49
52
blob , err := os .ReadFile (f )
50
53
if err != nil {
51
54
t .Fatal (err )
52
55
}
56
+ h .Write (blob )
53
57
seed = append (seed , migrate .RemoveRollbackStatements (string (blob )))
54
58
}
55
59
56
- uri , err := url .Parse (dburi )
57
- if err != nil {
58
- t .Fatal (err )
60
+ var name string
61
+ if rw {
62
+ name = fmt .Sprintf ("sqlc_test_%s" , id ())
63
+ } else {
64
+ name = fmt .Sprintf ("sqlc_test_%x" , h .Sum (nil ))
59
65
}
60
66
61
- name := fmt .Sprintf ("sqlc_test_%s" , id ())
62
-
63
- if _ , err := postgresPool .Exec (ctx , fmt .Sprintf (`CREATE DATABASE "%s"` , name )); err != nil {
67
+ uri , err := url .Parse (dburi )
68
+ if err != nil {
64
69
t .Fatal (err )
65
70
}
66
-
67
71
uri .Path = name
68
72
dropQuery := fmt .Sprintf (`DROP DATABASE IF EXISTS "%s" WITH (FORCE)` , name )
69
73
70
- t .Cleanup (func () {
71
- if _ , err := postgresPool .Exec (ctx , dropQuery ); err != nil {
72
- t .Fatal (err )
74
+ key := uri .String ()
75
+
76
+ _ , err , _ = flight .Do (key , func () (interface {}, error ) {
77
+ row := postgresPool .QueryRow (ctx ,
78
+ fmt .Sprintf (`SELECT datname FROM pg_database WHERE datname = '%s'` , name ))
79
+
80
+ var datname string
81
+ if err := row .Scan (& datname ); err == nil {
82
+ t .Logf ("database exists: %s" , name )
83
+ return nil , nil
73
84
}
74
- })
75
85
76
- conn , err := pgx .Connect (ctx , uri .String ())
77
- if err != nil {
78
- t .Fatalf ("connect %s: %s" , name , err )
79
- }
80
- defer conn .Close (ctx )
86
+ t .Logf ("creating database: %s" , name )
87
+ if _ , err := postgresPool .Exec (ctx , fmt .Sprintf (`CREATE DATABASE "%s"` , name )); err != nil {
88
+ return nil , err
89
+ }
81
90
82
- for _ , q := range seed {
83
- if len ( strings . TrimSpace ( q )) == 0 {
84
- continue
91
+ conn , err := pgx . Connect ( ctx , uri . String ())
92
+ if err != nil {
93
+ return nil , fmt . Errorf ( "connect %s: %s" , name , err )
85
94
}
86
- if _ , err := conn .Exec (ctx , q ); err != nil {
87
- t .Fatalf ("%s: %s" , q , err )
95
+ defer conn .Close (ctx )
96
+
97
+ for _ , q := range seed {
98
+ if len (strings .TrimSpace (q )) == 0 {
99
+ continue
100
+ }
101
+ if _ , err := conn .Exec (ctx , q ); err != nil {
102
+ return nil , fmt .Errorf ("%s: %s" , q , err )
103
+ }
88
104
}
105
+ return nil , nil
106
+ })
107
+ if rw || err != nil {
108
+ t .Cleanup (func () {
109
+ if _ , err := postgresPool .Exec (ctx , dropQuery ); err != nil {
110
+ t .Fatalf ("failed cleaning up: %s" , err )
111
+ }
112
+ })
89
113
}
90
-
91
- return uri .String ()
114
+ if err != nil {
115
+ t .Fatalf ("create db: %s" , err )
116
+ }
117
+ return key
92
118
}
0 commit comments