-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpostgres.go
More file actions
108 lines (95 loc) · 2.24 KB
/
postgres.go
File metadata and controls
108 lines (95 loc) · 2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package tmppg
import (
"context"
"fmt"
"io"
"log/slog"
"os/exec"
)
type Postgres struct {
stdout, stderr io.Writer
noSync bool
logStatement string
}
type Option func(pg *Postgres)
func NewPostgres(opts ...Option) *Postgres {
pg := &Postgres{
logStatement: "none",
}
for _, opt := range opts {
opt(pg)
}
return pg
}
type slogOut struct {
logger *slog.Logger
level slog.Level
}
func (s slogOut) Write(p []byte) (n int, err error) {
s.logger.Log(context.Background(), s.level, string(p))
return len(p), nil
}
func WithLogOutput(logger *slog.Logger, level slog.Level) Option {
return func(pg *Postgres) {
pg.stdout = slogOut{logger.With(slog.String("output", "stdout")), level}
pg.stderr = slogOut{logger.With(slog.String("output", "stderr")), level}
}
}
func WithOutput(stdout, stderr io.Writer) Option {
return func(pg *Postgres) {
pg.stdout = stdout
pg.stderr = stderr
}
}
// WithoutSync allows disabling syncing if data integrity isn't important
func WithoutSync() Option {
return func(pg *Postgres) {
pg.noSync = true
}
}
// WithLogStatement configures postgres' log_statement setting.
// Possible values are none, ddl, mod and all. Defaults to none.
func WithLogStatement(setting string) Option {
return func(pg *Postgres) {
pg.logStatement = setting
}
}
func (pg *Postgres) makeCmd(args ...string) *exec.Cmd {
cmd := exec.Command(args[0], args[1:]...)
cmd.Stdout = pg.stdout
cmd.Stderr = pg.stderr
return cmd
}
func (pg *Postgres) initDB(dir string) error {
args := []string{"initdb", "-D", dir, "--no-instructions"}
if pg.noSync {
args = append(args, "--no-sync")
}
cmd := pg.makeCmd(args...)
if err := cmd.Run(); err != nil {
return fmt.Errorf("exec: %w", err)
}
return nil
}
func (pg *Postgres) start(dir string) (*exec.Cmd, error) {
args := []string{
"postgres", "-D", dir,
"--listen_addresses=",
"--unix_socket_directories=" + dir,
"--log_line_prefix=[%p] ",
"--log_statement=" + pg.logStatement,
}
if pg.noSync {
args = append(
args,
"--fsync=off",
"--synchronous_commit=off",
"--full_page_writes=off",
)
}
pgCmd := pg.makeCmd(args...)
if err := pgCmd.Start(); err != nil {
return nil, fmt.Errorf("start postgres with args %v: %w", pgCmd.Args, err)
}
return pgCmd, nil
}