-
Notifications
You must be signed in to change notification settings - Fork 402
/
db.go
137 lines (113 loc) · 2.87 KB
/
db.go
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package pgutil
import (
"database/sql"
"strings"
"github.com/lib/pq"
"github.com/zeebo/errs"
monkit "gopkg.in/spacemonkeygo/monkit.v2"
"storj.io/storj/internal/dbutil"
"storj.io/storj/internal/dbutil/dbschema"
"storj.io/storj/internal/errs2"
)
// DB is postgres database with schema
type DB struct {
*sql.DB
Schema string
}
var (
mon = monkit.Package()
)
// Open opens a postgres database with a schema
func Open(connstr string, schemaPrefix string) (*DB, error) {
schemaName := schemaPrefix + "-" + CreateRandomTestingSchemaName(8)
db, err := sql.Open("postgres", ConnstrWithSchema(connstr, schemaName))
if err != nil {
return nil, err
}
dbutil.Configure(db, mon)
err = CreateSchema(db, schemaName)
if err != nil {
return nil, errs.Combine(err, db.Close())
}
return &DB{db, schemaName}, err
}
// Close closes the database and deletes the schema.
func (db *DB) Close() error {
return errs.Combine(
DropSchema(db.DB, db.Schema),
db.DB.Close(),
)
}
// LoadSchemaFromSQL inserts script into connstr and loads schema.
func LoadSchemaFromSQL(connstr, script string) (_ *dbschema.Schema, err error) {
db, err := Open(connstr, "load-schema")
if err != nil {
return nil, err
}
defer func() { err = errs.Combine(err, db.Close()) }()
_, err = db.Exec(script)
if err != nil {
return nil, err
}
return QuerySchema(db)
}
// LoadSnapshotFromSQL inserts script into connstr and loads schema.
func LoadSnapshotFromSQL(connstr, script string) (_ *dbschema.Snapshot, err error) {
db, err := Open(connstr, "load-schema")
if err != nil {
return nil, err
}
defer func() { err = errs.Combine(err, db.Close()) }()
_, err = db.Exec(script)
if err != nil {
return nil, err
}
snapshot, err := QuerySnapshot(db)
if err != nil {
return nil, err
}
snapshot.Script = script
return snapshot, nil
}
// QuerySnapshot loads snapshot from database
func QuerySnapshot(db dbschema.Queryer) (*dbschema.Snapshot, error) {
schema, err := QuerySchema(db)
if err != nil {
return nil, err
}
data, err := QueryData(db, schema)
if err != nil {
return nil, err
}
return &dbschema.Snapshot{
Version: -1,
Schema: schema,
Data: data,
}, err
}
//CheckApplicationName ensures that the Connection String contains an application name
func CheckApplicationName(s string) (r string) {
if !strings.Contains(s, "application_name") {
if !strings.Contains(s, "?") {
r = s + "?application_name=Satellite"
return
}
r = s + "&application_name=Satellite"
return
}
//return source as is if application_name is set
return s
}
// IsConstraintError checks if given error is about constraint violation
func IsConstraintError(err error) bool {
return errs2.IsFunc(err, func(err error) bool {
if e, ok := err.(*pq.Error); ok {
if e.Code.Class() == "23" {
return true
}
}
return false
})
}