mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-18 11:46:23 -07:00
Add post migration in place
This commit is contained in:
parent
cec68cb29b
commit
f0f0f055da
6 changed files with 210 additions and 7 deletions
|
@ -38,7 +38,7 @@ func (m *Pre2021Migrator) migrateBoardsInPlace() error {
|
|||
return err
|
||||
}
|
||||
|
||||
for _, statement := range alterStatements {
|
||||
for _, statement := range boardAlterStatements {
|
||||
if strings.Contains(statement, "CONSTRAINT") && m.db.SQLDriver() == "sqlite3" {
|
||||
// skip constraints in SQLite since they can't be added after table creation
|
||||
continue
|
||||
|
|
|
@ -3,6 +3,8 @@ package pre2021
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gochan-org/gochan/cmd/gochan-migration/internal/common"
|
||||
|
@ -195,5 +197,153 @@ func (m *Pre2021Migrator) migratePostsToNewDB() error {
|
|||
}
|
||||
|
||||
func (m *Pre2021Migrator) migratePostsInPlace() error {
|
||||
return common.NewMigrationError("pre2021", "not yet implemented")
|
||||
errEv := common.LogError()
|
||||
defer errEv.Discard()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(m.config.DBTimeoutSeconds))
|
||||
defer cancel()
|
||||
|
||||
ba, err := os.ReadFile(gcutil.FindResource("sql/initdb_" + m.db.SQLDriver() + ".sql"))
|
||||
if err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Msg("Failed to read initdb SQL file")
|
||||
return err
|
||||
}
|
||||
statements := strings.Split(string(ba), ";")
|
||||
for _, statement := range statements {
|
||||
statement = strings.TrimSpace(statement)
|
||||
if strings.HasPrefix(statement, "CREATE TABLE DBPREFIXthreads") || strings.HasPrefix(statement, "CREATE TABLE DBPREFIXfiles") {
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil, statement); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to create threads table")
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rows, err := m.db.QueryContextSQL(ctx, nil, threadsQuery+" AND parentid = 0")
|
||||
if err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Msg("Failed to get threads")
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var threads []migrationPost
|
||||
for rows.Next() {
|
||||
var post migrationPost
|
||||
if err = rows.Scan(
|
||||
&post.ID, &post.oldBoardID, &post.oldParentID, &post.Name, &post.Tripcode, &post.Email,
|
||||
&post.Subject, &post.Message, &post.MessageRaw, &post.Password, &post.filename,
|
||||
&post.filenameOriginal, &post.fileChecksum, &post.filesize, &post.imageW, &post.imageH,
|
||||
&post.thumbW, &post.thumbH, &post.IP, &post.CreatedOn, &post.autosage,
|
||||
&post.bumped, &post.stickied, &post.locked,
|
||||
); err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Msg("Failed to scan thread")
|
||||
return err
|
||||
}
|
||||
threads = append(threads, post)
|
||||
}
|
||||
if err = rows.Close(); err != nil {
|
||||
errEv.Caller().Msg("Failed to close thread rows")
|
||||
return err
|
||||
}
|
||||
|
||||
for _, statements := range postAlterStatements {
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil, statements); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to alter posts table")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
switch m.db.SQLDriver() {
|
||||
case "mysql":
|
||||
_, err = m.db.ExecContextSQL(ctx, nil, "ALTER TABLE DBPREFIXposts ADD COLUMN ip_new VARBINARY(16) NOT NULL")
|
||||
case "postgres", "postgresql":
|
||||
_, err = m.db.ExecContextSQL(ctx, nil, "ALTER TABLE DBPREFIXposts ADD COLUMN ip_new INET NOT NULL")
|
||||
case "sqlite3":
|
||||
_, err = m.db.ExecContextSQL(ctx, nil, "ALTER TABLE DBPREFIXposts ADD COLUMN ip_new VARCHAR(45) NOT NULL DEFAULT '0.0.0.0'")
|
||||
}
|
||||
if err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to update IP column")
|
||||
return err
|
||||
}
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil, "UPDATE DBPREFIXposts SET ip_new = IP_ATON"); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to update IP column")
|
||||
return err
|
||||
}
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil, "ALTER TABLE DBPREFIXposts RENAME COLUMN ip TO ip_old"); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to rename old IP column")
|
||||
return err
|
||||
}
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil, "ALTER TABLE DBPREFIXposts RENAME COLUMN ip_new TO ip"); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to rename new IP column")
|
||||
return err
|
||||
}
|
||||
|
||||
for _, op := range threads {
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil,
|
||||
`INSERT INTO DBPREFIXthreads(board_id,locked,stickied,anchored,cyclical,last_bump,is_deleted) VALUES(?,?,?,?,?,?,?)`,
|
||||
op.oldBoardID, op.locked, op.stickied, op.autosage, false, op.bumped, false,
|
||||
); err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postID", op.ID).
|
||||
Msg("Failed to insert thread")
|
||||
return err
|
||||
}
|
||||
if err = m.db.QueryRowContextSQL(ctx, nil, "SELECT MAX(id) FROM DBPREFIXthreads", nil, []any{&op.ThreadID}); err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postID", op.ID).
|
||||
Msg("Failed to get thread ID")
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil,
|
||||
"UPDATE DBPREFIXposts SET thread_id = ? WHERE (id = ? and is_top_post) or thread_id = ?", op.ThreadID, op.oldID, op.oldID,
|
||||
); err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postID", op.ID).
|
||||
Int("threadID", op.ThreadID).
|
||||
Msg("Failed to set thread ID")
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rows, err = m.db.QueryContextSQL(ctx, nil,
|
||||
"SELECT id,filename,filename_original,file_checksum,filesize,image_w,image_h,thumb_w,thumb_h FROM DBPREFIXposts WHERE filename <> ''",
|
||||
); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to get uploads")
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var uploads []gcsql.Upload
|
||||
for rows.Next() {
|
||||
var upload gcsql.Upload
|
||||
if err = rows.Scan(&upload.PostID, &upload.Filename, &upload.OriginalFilename, &upload.Checksum, &upload.FileSize, &upload.Width,
|
||||
&upload.Height, &upload.ThumbnailWidth, &upload.ThumbnailHeight,
|
||||
); err != nil {
|
||||
errEv.Err(err).Caller().Msg("Failed to scan upload")
|
||||
return err
|
||||
}
|
||||
uploads = append(uploads, upload)
|
||||
}
|
||||
if err = rows.Close(); err != nil {
|
||||
errEv.Caller().Msg("Failed to close upload rows")
|
||||
return err
|
||||
}
|
||||
|
||||
for _, upload := range uploads {
|
||||
if _, err = m.db.ExecContextSQL(ctx, nil,
|
||||
`INSERT INTO DBPREFIXfiles(post_id,file_order,filename,original_filename,checksum,file_size,width,height,thumbnail_width,thumbnail_height,is_spoilered) VALUES
|
||||
(?,0,?,?,?,?,?,?,?,?,0)`,
|
||||
upload.PostID, upload.Filename, upload.OriginalFilename, upload.Checksum, upload.FileSize, upload.Width, upload.Height,
|
||||
upload.ThumbnailWidth, upload.ThumbnailHeight,
|
||||
); err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Int("postID", upload.PostID).
|
||||
Msg("Failed to insert upload")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -49,3 +49,32 @@ func TestMigratePostsToNewDB(t *testing.T) {
|
|||
assert.NoError(t, gcsql.QueryRowSQL("SELECT COUNT(*) FROM DBPREFIXfiles", nil, []any{&numUploadPosts}))
|
||||
assert.Equal(t, 1, numUploadPosts, "Expected to have 1 upload post")
|
||||
}
|
||||
|
||||
func TestMigratePostsInPlace(t *testing.T) {
|
||||
outDir := t.TempDir()
|
||||
migrator := setupMigrationTest(t, outDir, true)
|
||||
if !assert.True(t, migrator.IsMigratingInPlace(), "This test should be migrating in place") {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !assert.NoError(t, migrator.MigrateBoards()) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !assert.NoError(t, migrator.MigratePosts()) {
|
||||
t.FailNow()
|
||||
}
|
||||
var numThreads int
|
||||
if !assert.NoError(t, gcsql.QueryRowSQL("SELECT COUNT(*) FROM DBPREFIXthreads", nil, []any{&numThreads}), "Failed to get number of threads") {
|
||||
t.FailNow()
|
||||
}
|
||||
assert.Equal(t, 2, numThreads, "Expected to have two threads pre-migration")
|
||||
|
||||
var numUploadPosts int
|
||||
assert.NoError(t, gcsql.QueryRowSQL("SELECT COUNT(*) FROM DBPREFIXfiles", nil, []any{&numUploadPosts}))
|
||||
assert.Equal(t, 1, numUploadPosts, "Expected to have 1 upload post")
|
||||
|
||||
var ip string
|
||||
assert.NoError(t, gcsql.QueryRowSQL("SELECT IP_NTOA FROM DBPREFIXposts WHERE id = 1", nil, []any{&ip}))
|
||||
assert.Equal(t, "192.168.56.1", ip, "Expected to have the correct IP address")
|
||||
}
|
||||
|
|
|
@ -90,13 +90,24 @@ func setupMigrationTest(t *testing.T, outDir string, migrateInPlace bool) *Pre20
|
|||
return migrator
|
||||
}
|
||||
|
||||
func TestPre2021Migration(t *testing.T) {
|
||||
func TestPre2021MigrationToNewDB(t *testing.T) {
|
||||
outDir := t.TempDir()
|
||||
migrator := setupMigrationTest(t, outDir, false)
|
||||
if !assert.False(t, migrator.IsMigratingInPlace(), "This test should not be migrating in place") {
|
||||
t.FailNow()
|
||||
}
|
||||
migrated, err := migrator.MigrateDB()
|
||||
assert.False(t, migrated)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, migrated)
|
||||
}
|
||||
|
||||
func TestPre2021MigrationInPlace(t *testing.T) {
|
||||
outDir := t.TempDir()
|
||||
migrator := setupMigrationTest(t, outDir, true)
|
||||
if !assert.True(t, migrator.IsMigratingInPlace(), "This test should be migrating in place") {
|
||||
t.FailNow()
|
||||
}
|
||||
migrated, err := migrator.MigrateDB()
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, migrated)
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ timestamp, expires, permaban, reason, type, staff_note, appeal_at, can_appeal FR
|
|||
)
|
||||
|
||||
var (
|
||||
alterStatements = []string{
|
||||
boardAlterStatements = []string{
|
||||
"ALTER TABLE DBPREFIXboards RENAME COLUMN section TO section_id",
|
||||
"ALTER TABLE DBPREFIXboards RENAME COLUMN list_order TO navbar_position",
|
||||
"ALTER TABLE DBPREFIXboards RENAME COLUMN created_on TO created_at",
|
||||
|
@ -39,4 +39,17 @@ var (
|
|||
"ALTER TABLE DBPREFIXboards ADD CONSTRAINT boards_dir_unique UNIQUE (dir)",
|
||||
"ALTER TABLE DBPREFIXboards ADD CONSTRAINT boards_uri_unique UNIQUE (uri)",
|
||||
}
|
||||
postAlterStatements = []string{
|
||||
"ALTER TABLE DBPREFIXposts RENAME COLUMN parentid TO thread_id",
|
||||
"ALTER TABLE DBPREFIXposts RENAME COLUMN timestamp TO created_on",
|
||||
"ALTER TABLE DBPREFIXposts RENAME COLUMN deleted_timestamp TO deleted_at",
|
||||
// "ALTER TABLE DBPREFIXposts RENAME COLUMN ip TO ip_old",
|
||||
"ALTER TABLE DBPREFIXposts ADD COLUMN is_top_post BOOL NOT NULL DEFAULT FALSE",
|
||||
"ALTER TABLE DBPREFIXposts ADD COLUMN is_role_signature BOOL NOT NULL DEFAULT FALSE",
|
||||
"ALTER TABLE DBPREFIXposts ADD COLUMN is_deleted BOOL NOT NULL DEFAULT FALSE",
|
||||
"ALTER TABLE DBPREFIXposts ADD COLUMN banned_message TEXT",
|
||||
"ALTER TABLE DBPREFIXposts ADD COLUMN flag VARCHAR(45) NOT NULL DEFAULT ''",
|
||||
"ALTER TABLE DBPREFIXposts ADD COLUMN country VARCHAR(80) NOT NULL DEFAULT ''",
|
||||
"UPDATE DBPREFIXposts SET is_top_post = TRUE WHERE thread_id = 0",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -12,8 +12,8 @@ import (
|
|||
)
|
||||
|
||||
func (*Pre2021Migrator) migrateStaffInPlace() error {
|
||||
err := common.NewMigrationError("pre2021", "migrateSectionsInPlace not yet implemented")
|
||||
common.LogError().Err(err).Caller().Msg("Failed to migrate sections")
|
||||
err := common.NewMigrationError("pre2021", "migrateStaff not yet implemented")
|
||||
common.LogError().Err(err).Caller().Msg("Failed to migrate staff")
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue