diff --git a/cmd/backend/articles_authors.go b/cmd/backend/articles_authors.go new file mode 100644 index 0000000..d5b89f5 --- /dev/null +++ b/cmd/backend/articles_authors.go @@ -0,0 +1,114 @@ +package backend + +import ( + "fmt" + "log" +) + +func (db *DB) WriteArticleAuthors(articleID int64, authorIDs []int64) error { + query := "INSERT INTO articles_authors (article_id, author_id) VALUES (?, ?)" + + for i := 0; i < TxMaxRetries; i++ { + err := func() error { + tx, err := db.Begin() + if err != nil { + return fmt.Errorf("error starting transaction: %v", err) + } + + for _, authorID := range authorIDs { + if _, err := tx.Exec(query, articleID, authorID); err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr) + } + return fmt.Errorf("error inserting into articles_authors: %v", err) + } + } + + if err = tx.Commit(); err != nil { + return fmt.Errorf("error committing transaction: %v", err) + } + return nil + }() + if err == nil { + return nil + } + + log.Println(err) + wait(i) + } + return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries) +} + +func (db *DB) GetArticleAuthors(c *Config, articleID int64) ([]*User, error) { + query := ` + SELECT u.id + FROM articles a + INNER JOIN articles_tags at ON a.id = at.article_id + INNER JOIN users u ON at.author_id = u.id + WHERE a.id = ? + ` + rows, err := db.Query(query, articleID) + if err != nil { + return nil, fmt.Errorf("error querying articles_authors: %v", err) + } + + authors := make([]*User, 0) + for rows.Next() { + var authorID int64 + + if err = rows.Scan(&authorID); err != nil { + return nil, fmt.Errorf("error scanning rows: %v", err) + } + + author, err := db.GetUser(c, authorID) + if err != nil { + return nil, fmt.Errorf("error getting user info for article author: %v", err) + } + + authors = append(authors, author) + } + + return authors, nil +} + +func (db *DB) UpdateArticleAuthors(articleID int64, authorIDs []int64) error { + deleteQuery := "DELETE FROM articles_authors WHERE article_id = ?" + insertQuery := "INSERT INTO articles_authors (article_id, author_id) VALUES (?, ?)" + + for i := 0; i < TxMaxRetries; i++ { + err := func() error { + tx, err := db.Begin() + if err != nil { + return fmt.Errorf("error starting transaction: %v", err) + } + + if _, err := tx.Exec(deleteQuery, articleID); err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr) + } + return fmt.Errorf("error deleting entries from articles_authors before inserting new ones: %v", err) + } + + for _, authorID := range authorIDs { + if _, err := tx.Exec(insertQuery, articleID, authorID); err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr) + } + return fmt.Errorf("error inserting new entries into articles_authors: %v", err) + } + } + + if err = tx.Commit(); err != nil { + return fmt.Errorf("error committing transaction: %v", err) + } + return nil + }() + if err == nil { + return nil + } + + log.Println(err) + wait(i) + } + return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries) +} diff --git a/cmd/backend/articles_contributors.go b/cmd/backend/articles_contributors.go new file mode 100644 index 0000000..2f3da69 --- /dev/null +++ b/cmd/backend/articles_contributors.go @@ -0,0 +1,114 @@ +package backend + +import ( + "fmt" + "log" +) + +func (db *DB) WriteArticleContributors(articleID int64, contributorIDs []int64) error { + query := "INSERT INTO articles_contributors (article_id, contributor_id) VALUES (?, ?)" + + for i := 0; i < TxMaxRetries; i++ { + err := func() error { + tx, err := db.Begin() + if err != nil { + return fmt.Errorf("error starting transaction: %v", err) + } + + for _, contributorID := range contributorIDs { + if _, err := tx.Exec(query, articleID, contributorID); err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr) + } + return fmt.Errorf("error inserting into articles_contributors: %v", err) + } + } + + if err = tx.Commit(); err != nil { + return fmt.Errorf("error committing transaction: %v", err) + } + return nil + }() + if err == nil { + return nil + } + + log.Println(err) + wait(i) + } + return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries) +} + +func (db *DB) GetArticleContributors(c *Config, articleID int64) ([]*User, error) { + query := ` + SELECT u.id + FROM articles a + INNER JOIN articles_tags at ON a.id = at.article_id + INNER JOIN users u ON at.contributor_id = u.id + WHERE a.id = ? + ` + rows, err := db.Query(query, articleID) + if err != nil { + return nil, fmt.Errorf("error querying articles_contributors: %v", err) + } + + contributors := make([]*User, 0) + for rows.Next() { + var contributorID int64 + + if err = rows.Scan(&contributorID); err != nil { + return nil, fmt.Errorf("error scanning rows: %v", err) + } + + contributor, err := db.GetUser(c, contributorID) + if err != nil { + return nil, fmt.Errorf("error getting user info for article contributor: %v", err) + } + + contributors = append(contributors, contributor) + } + + return contributors, nil +} + +func (db *DB) UpdateArticleContributors(articleID int64, contributorIDs []int64) error { + deleteQuery := "DELETE FROM articles_contributors WHERE article_id = ?" + insertQuery := "INSERT INTO articles_contributors (article_id, contributor_id) VALUES (?, ?)" + + for i := 0; i < TxMaxRetries; i++ { + err := func() error { + tx, err := db.Begin() + if err != nil { + return fmt.Errorf("error starting transaction: %v", err) + } + + if _, err := tx.Exec(deleteQuery, articleID); err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr) + } + return fmt.Errorf("error deleting entries from articles_contributors before inserting new ones: %v", err) + } + + for _, contributorID := range contributorIDs { + if _, err := tx.Exec(insertQuery, articleID, contributorID); err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr) + } + return fmt.Errorf("error inserting new entries into articles_contributors: %v", err) + } + } + + if err = tx.Commit(); err != nil { + return fmt.Errorf("error committing transaction: %v", err) + } + return nil + }() + if err == nil { + return nil + } + + log.Println(err) + wait(i) + } + return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries) +}