-
Notifications
You must be signed in to change notification settings - Fork 0
/
database.go
109 lines (90 loc) · 3.06 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
package database
import (
"context"
"database/sql"
"fmt"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
)
var (
// Sample of the [User] database model.
sampleUser = (*User)(nil)
// Sample of the [Category] database model.
sampleCategory = (*Category)(nil)
// Sample of the [Currency] database model.
sampleCurrency = (*Currency)(nil)
// Sample of the [Transaction] database model.
sampleTransaction = (*Transaction)(nil)
)
var (
// Model samples which are used to create tables.
models = []any{sampleUser, sampleUser, sampleCurrency, sampleTransaction}
// PostgreSQL extensions that must be created.
extensions = []string{"uuid-ossp"}
)
// Credentials represents the credentials required to connect to a PostgreSQL database.
// It includes fields for the hostname, port number, username, password, and the name
// of the database to connect to.
type Credentials struct {
Host string
Port int
User string
Password string
Database string
}
// Database is an interface that abstracts the functionality of a database system.
// It provides methods for testing the connection to the database, initializing it,
// and accessing various data querying operations related to users, categories,
// currencies, and transactions.
type Database interface {
// TestConnection verifies the connection to the database.
TestConnection() error
// Init initializes the database with any necessary setup procedures.
// It accepts a context.Context for handling cancellation signals.
Init(ctx context.Context) error
UserQuerier
CategoryQuerier
CurrencyQuerier
TransactionQuerier
}
// DefaultDatabase is the default implementation of the Database interface.
// It encapsulates a client for interacting with the database.
type DefaultDatabase struct {
client *bun.DB
}
// New creates a new instance of DefaultDatabase initialized with the provided
// credentials and returns a pointer to it. It establishes a connection to the
// PostgreSQL database using the provided credentials.
func New(c Credentials) *DefaultDatabase {
dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", c.User, c.Password, c.Host, c.Port, c.Database)
sqlDb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
bunDb := bun.NewDB(sqlDb, pgdialect.New())
return &DefaultDatabase{
client: bunDb,
}
}
// TestConnection verifies database connection.
func (d *DefaultDatabase) TestConnection() error {
if err := d.client.Ping(); err != nil {
return err
}
return nil
}
// Init creates all necessary tables and extensions if they do not exist.
func (d *DefaultDatabase) Init(ctx context.Context) error {
// create necessary extensions if they do not exist:
for _, extension := range extensions {
if _, err := d.client.NewRaw("CREATE EXTENSION IF NOT EXISTS ?;", bun.Ident(extension)).Exec(ctx); err != nil {
return err
}
}
// create necessary tables if they do not exist:
for _, model := range models {
_, err := d.client.NewCreateTable().Model(model).IfNotExists().Exec(ctx)
if err != nil {
return err
}
}
return nil
}