posthooks.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: Apache-2.0
 4
 5package db
 6
 7import (
 8	"crypto/sha256"
 9	"database/sql"
10	"fmt"
11)
12
13// generateAndInsertProjectIDs runs during migration 1, fetches all rows from
14// projects_tmp, loops through the rows generating a repeatable ID for each
15// project, and inserting it into the new table along with the data from the old
16// table.
17func generateAndInsertProjectIDs(transaction *sql.Tx) error {
18	// Loop through projects_tmp, generate a project_id for each, and insert
19	// into projects
20	rows, err := transaction.Query("SELECT url, name, forge, version, created_at FROM projects_tmp")
21	if err != nil {
22		return fmt.Errorf("failed to list projects in projects_tmp: %w", err)
23	}
24	defer rows.Close()
25
26	for rows.Next() {
27		var (
28			url        string
29			name       string
30			forge      string
31			version    string
32			created_at string
33		)
34		if err := rows.Scan(&url, &name, &forge, &version, &created_at); err != nil {
35			return fmt.Errorf("failed to scan row from projects_tmp: %w", err)
36		}
37		id := fmt.Sprintf("%x", sha256.Sum256([]byte(url+name+forge+created_at)))
38		_, err = transaction.Exec(
39			"INSERT INTO projects (id, url, name, forge, version, created_at) VALUES (@id, @url, @name, @forge, @version, @created_at)",
40			sql.Named("id", id),
41			sql.Named("url", url),
42			sql.Named("name", name),
43			sql.Named("forge", forge),
44			sql.Named("version", version),
45			sql.Named("created_at", created_at),
46		)
47		if err != nil {
48			return fmt.Errorf("failed to insert project into projects: %w", err)
49		}
50	}
51
52	if _, err := transaction.Exec("DROP TABLE projects_tmp"); err != nil {
53		return fmt.Errorf("failed to drop projects_tmp: %w", err)
54	}
55
56	if err := rows.Err(); err != nil {
57		return fmt.Errorf("failed during row iteration for projects_tmp: %w", err)
58	}
59
60	return nil
61}
62
63// Basing the project's ID on when it was created (L37) was a bad idea.
64func correctProjectIDs(transaction *sql.Tx) error {
65	rows, err := transaction.Query("SELECT id, url, name, forge FROM projects")
66	if err != nil {
67		return fmt.Errorf("failed to list projects in projects_tmp: %w", err)
68	}
69	defer rows.Close()
70
71	for rows.Next() {
72		var (
73			old_id string
74			url    string
75			name   string
76			forge  string
77		)
78		if err := rows.Scan(&old_id, &url, &name, &forge); err != nil {
79			return fmt.Errorf("failed to scan row from projects_tmp: %w", err)
80		}
81		id := fmt.Sprintf("%x", sha256.Sum256([]byte(url+name+forge)))
82		_, err = transaction.Exec(
83			"UPDATE projects SET id = @id WHERE id = @old_id",
84			sql.Named("id", id),
85			sql.Named("old_id", old_id),
86		)
87		if err != nil {
88			return fmt.Errorf("failed to insert project into projects: %w", err)
89		}
90	}
91
92	if err := rows.Err(); err != nil {
93		return fmt.Errorf("failed during row iteration for projects_tmp: %w", err)
94	}
95
96	return nil
97}