-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdialects.go
More file actions
78 lines (59 loc) · 2.48 KB
/
dialects.go
File metadata and controls
78 lines (59 loc) · 2.48 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
// SPDX-FileCopyrightText: 2026 The DMorph contributors.
// SPDX-License-Identifier: MPL-2.0
package dmorph
import (
"context"
"database/sql"
"errors"
"fmt"
)
// BaseDialect is a convenience type for databases that manage the necessary operations solely using
// queries. Defining the CreateTemplate, AppliedTemplate and RegisterTemplate enables the BaseDialect to
// perform all the necessary operations to fulfill the Dialect interface.
type BaseDialect struct {
CreateTemplate string // statement ensuring the existence of the migration table
AppliedTemplate string // statement getting applied migrations ordered by application date
RegisterTemplate string // statement registering a migration
}
// EnsureMigrationTableExists ensures that the migration table, saving the applied migrations ids, exists.
func (b BaseDialect) EnsureMigrationTableExists(ctx context.Context, db *sql.DB, tableName string) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return wrapIfError("could not start transaction", err)
}
// Safety net for unexpected panics or returns. We can always call Rollback,
// as it does semantically nothing in case of a previous successful commit
defer func() { _ = tx.Rollback() }()
if _, execErr := tx.ExecContext(ctx, fmt.Sprintf(b.CreateTemplate, tableName)); execErr != nil {
rollbackErr := tx.Rollback()
return errors.Join(execErr, rollbackErr)
}
if err := tx.Commit(); err != nil {
rollbackErr := tx.Rollback()
return errors.Join(err, rollbackErr)
}
return nil
}
// AppliedMigrations gets the already applied migrations from the database, ordered by application date.
func (b BaseDialect) AppliedMigrations(ctx context.Context, db *sql.DB, tableName string) ([]string, error) {
rows, rowsErr := db.QueryContext(ctx, fmt.Sprintf(b.AppliedTemplate, tableName))
if rowsErr != nil {
return nil, wrapIfError("could not get applied migrations", rowsErr)
}
defer func() { _ = rows.Close() }()
var result []string
var tmp string
var scanErr error
for rows.Next() && scanErr == nil {
if scanErr = rows.Scan(&tmp); scanErr == nil {
result = append(result, tmp)
}
}
return result, errors.Join(rows.Err(), scanErr)
}
// RegisterMigration registers a migration in the migration table.
func (b BaseDialect) RegisterMigration(ctx context.Context, tx *sql.Tx, id string, tableName string) error {
_, err := tx.ExecContext(ctx, fmt.Sprintf(b.RegisterTemplate, tableName),
sql.Named("id", id))
return wrapIfError("could not register migration", err)
}