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(tx *sql.Tx) error {
18 // Loop through projects_tmp, generate a project_id for each, and insert
19 // into projects
20 rows, err := tx.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 createdAt string
33 )
34 if err := rows.Scan(&url, &name, &forge, &version, &createdAt); err != nil {
35 return fmt.Errorf("failed to scan row from projects_tmp: %w", err)
36 }
37
38 id := fmt.Sprintf("%x", sha256.Sum256([]byte(url+name+forge+createdAt)))
39
40 _, err = tx.Exec(
41 "INSERT INTO projects (id, url, name, forge, version, created_at) "+
42 "VALUES (@id, @url, @name, @forge, @version, @created_at)",
43 sql.Named("id", id),
44 sql.Named("url", url),
45 sql.Named("name", name),
46 sql.Named("forge", forge),
47 sql.Named("version", version),
48 sql.Named("created_at", createdAt),
49 )
50 if err != nil {
51 return fmt.Errorf("failed to insert project into projects: %w", err)
52 }
53 }
54
55 if err := rows.Err(); err != nil {
56 return fmt.Errorf("failed to iterate over rows: %w", err)
57 }
58
59 if _, err := tx.Exec("DROP TABLE projects_tmp"); err != nil {
60 return fmt.Errorf("failed to drop projects_tmp: %w", err)
61 }
62
63 return nil
64}
65
66// Basing the project's ID on when it was created (L37) was a bad idea.
67func correctProjectIDs(tx *sql.Tx) error {
68 rows, err := tx.Query("SELECT id, url, name, forge FROM projects")
69 if err != nil {
70 return fmt.Errorf("failed to list projects in projects_tmp: %w", err)
71 }
72 defer rows.Close()
73
74 for rows.Next() {
75 var (
76 oldID string
77 url string
78 name string
79 forge string
80 )
81 if err := rows.Scan(&oldID, &url, &name, &forge); err != nil {
82 return fmt.Errorf("failed to scan row from projects_tmp: %w", err)
83 }
84
85 id := fmt.Sprintf("%x", sha256.Sum256([]byte(url+name+forge)))
86
87 _, err = tx.Exec(
88 "UPDATE projects SET id = @id WHERE id = @old_id",
89 sql.Named("id", id),
90 sql.Named("old_id", oldID),
91 )
92 if err != nil {
93 return fmt.Errorf("failed to insert project into projects: %w", err)
94 }
95 }
96
97 if err := rows.Err(); err != nil {
98 return fmt.Errorf("failed to iterate over rows: %w", err)
99 }
100
101 return nil
102}