-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdatabase.go
125 lines (115 loc) · 3.42 KB
/
database.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
package goose
import (
"context"
"errors"
"fmt"
"os"
"time"
"github.com/go-playground/validator/v10"
"github.com/joho/godotenv"
log "github.com/sirupsen/logrus"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
// Database is a base struct for goose mongo
type Database struct {
DB *mongo.Database
Client *mongo.Client
Context context.Context
}
type databaseEnvSetting struct {
username string
password string
endpoint string
port string
}
// DatabaseOptions init database options
type DatabaseOptions struct {
ConnectTimeout time.Duration `validate:"isdefault=5"` // Timeout operations after N seconds
URL string `validate:"required_without=UsingEnv"` // connection URL string
UsingEnv bool `validate:"required_without=URL"` // using env
DatabaseName string `validate:"required_without=UsingEnv"` // databaseName
databaseEnvSetting
}
// DB a mongo database instance after init
var DB *mongo.Database
func getMongoConnURLFromEnv(ops *DatabaseOptions) (string, error) {
username := os.Getenv("MONGODB_USERNAME")
password := os.Getenv("MONGODB_PASSWORD")
clusterEndpoint := os.Getenv("MONGODB_ENDPOINT")
port := os.Getenv("MONGODB_PORT")
if username == "" || password == "" || clusterEndpoint == "" || port == "" {
return "", errors.New("missing env")
}
log.WithFields(log.Fields{
"username": username,
"password": password,
"clusterEndpoint": clusterEndpoint,
})
mongoConnStringTemplate := "mongodb://%s:%s@%s:%s"
connectionURI := fmt.Sprintf(mongoConnStringTemplate, username, password, clusterEndpoint, port)
return connectionURI, nil
}
func validateOptions(ops *DatabaseOptions) error {
var validate = validator.New()
err := validate.Struct(ops)
if err != nil {
return err
}
log.WithField("ops", ops).Info("mongo database options.")
return nil
}
// NewMongoDatabase new a goose mongo database
func NewMongoDatabase(ops *DatabaseOptions) (*Database, error) {
err := validateOptions(ops)
if err != nil {
log.Error("database options not valid.")
return nil, err
}
var connectionURL string
var databaseName string
if ops.UsingEnv {
err := godotenv.Load()
if err != nil {
return nil, err
}
log.Info("using env URL.")
connectionURL, err = getMongoConnURLFromEnv(ops)
if err != nil {
return nil, err
}
databaseName = os.Getenv("MONGODB_DATABASE")
} else {
log.Info("using options URL.")
connectionURL = ops.URL
databaseName = ops.DatabaseName
}
ctx, cancel := context.WithTimeout(context.Background(), ops.ConnectTimeout*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, options.Client().ApplyURI(connectionURL))
if err != nil {
log.WithField("URL", connectionURL).Error("could not parse connection URL.")
return nil, err
}
ctxPING, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err = client.Ping(ctxPING, readpref.Primary())
if err != nil {
return nil, err
}
db := client.Database(databaseName)
mongoClient := &Database{DB: db, Client: client, Context: ctx}
log.Info("mongodb has been connected")
DB = mongoClient.DB
return mongoClient, nil
}
// Close close database connection
func (d *Database) Close() error {
err := d.Client.Disconnect(d.Context)
if err != nil {
log.WithField("message", err.Error()).Error("mongo database close error")
return err
}
return nil
}