aboutsummaryrefslogtreecommitdiff
blob: 53247fe85dee8e4907a609c14e74fb9e01b35ced (plain)
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
// Contains utility functions around the database

package database

import (
	"context"
	"log/slog"
	"os"
	"time"

	"github.com/go-pg/pg/v10"
	"github.com/go-pg/pg/v10/orm"

	"soko/pkg/config"
	"soko/pkg/models"
)

// DBCon is the connection handle
// for the database
var (
	DBCon *pg.DB
)

// CreateSchema creates the tables in the database
// in case they don't already exist
func CreateSchema() error {
	for _, model := range []interface{}{
		(*models.CommitToPackage)(nil),
		(*models.CommitToVersion)(nil),
		(*models.PackageToBug)(nil),
		(*models.VersionToBug)(nil),
		(*models.PackageToGithubPullRequest)(nil),
		(*models.MaskToVersion)(nil),
		(*models.DeprecatedToVersion)(nil),
		(*models.Package)(nil),
		(*models.CategoryPackagesInformation)(nil),
		(*models.Category)(nil),
		(*models.Version)(nil),
		(*models.Commit)(nil),
		(*models.KeywordChange)(nil),
		(*models.Useflag)(nil),
		(*models.Mask)(nil),
		(*models.DeprecatedPackage)(nil),
		(*models.OutdatedPackages)(nil),
		(*models.Project)(nil),
		(*models.MaintainerToProject)(nil),
		(*models.PkgCheckResult)(nil),
		(*models.GithubPullRequest)(nil),
		(*models.Bug)(nil),
		(*models.ReverseDependency)(nil),
		(*models.Maintainer)(nil),
		(*models.Application)(nil),
	} {
		err := DBCon.Model(model).CreateTable(&orm.CreateTableOptions{
			IfNotExists: true,
		})
		if err != nil {
			tableName := string(DBCon.Model(model).TableModel().Table().TypeName)
			slog.Error("Failed creating table", slog.String("table", tableName), slog.Any("err", err))
			return err
		}
	}
	_, err := DBCon.Exec("CREATE EXTENSION IF NOT EXISTS pg_trgm")
	if err != nil {
		slog.Error("Failed creating extension 'pg_trgm'", slog.Any("err", err))
		return err
	}

	return nil
}

type dbLogger struct{}

func (d dbLogger) BeforeQuery(c context.Context, q *pg.QueryEvent) (context.Context, error) {
	return c, nil
}

// AfterQuery is used to log SQL queries
func (d dbLogger) AfterQuery(c context.Context, q *pg.QueryEvent) error {
	query, err := q.FormattedQuery()
	if err == nil {
		slog.Debug(string(query), slog.Duration("duration", time.Since(q.StartTime)))
	}
	return nil
}

// Connect is used to connect to the database
// and turn on logging if desired
func Connect() {
	DBCon = pg.Connect(&pg.Options{
		User:     config.PostgresUser(),
		Password: config.PostgresPass(),
		Database: config.PostgresDb(),
		Addr:     config.PostgresHost() + ":" + config.PostgresPort(),
	})

	if !config.Quiet() {
		DBCon.AddQueryHook(dbLogger{})
	}

	err := CreateSchema()
	if err != nil {
		slog.Error("Failed creating database schema", slog.Any("err", err))
		os.Exit(1)
	}
}

func TruncateTable[K any](_ string) {
	query := DBCon.Model((*K)(nil))
	tableName := string(query.TableModel().Table().TypeName)
	_, err := query.Exec("TRUNCATE TABLE ?TableName")
	if err != nil {
		slog.Error("Failed truncating table", slog.String("table", tableName), slog.Any("err", err))
	} else {
		slog.Info("Truncated table", slog.String("table", tableName))
	}
}