mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:02:25 -05:00 
			
		
		
		
	[bugfix] add ON CONFLICT statements to status updates (#1580)
This commit is contained in:
		
					parent
					
						
							
								e6cde25466
							
						
					
				
			
			
				commit
				
					
						bfccf4e450
					
				
			
		
					 2 changed files with 43 additions and 6 deletions
				
			
		|  | @ -200,7 +200,9 @@ func (s *statusDB) PutStatus(ctx context.Context, status *gtsmodel.Status) db.Er | ||||||
| 					Model(>smodel.StatusToEmoji{ | 					Model(>smodel.StatusToEmoji{ | ||||||
| 						StatusID: status.ID, | 						StatusID: status.ID, | ||||||
| 						EmojiID:  i, | 						EmojiID:  i, | ||||||
| 					}).Exec(ctx); err != nil { | 					}). | ||||||
|  | 					On("CONFLICT (?, ?) DO NOTHING", bun.Ident("status_id"), bun.Ident("emoji_id")). | ||||||
|  | 					Exec(ctx); err != nil { | ||||||
| 					err = s.conn.ProcessError(err) | 					err = s.conn.ProcessError(err) | ||||||
| 					if !errors.Is(err, db.ErrAlreadyExists) { | 					if !errors.Is(err, db.ErrAlreadyExists) { | ||||||
| 						return err | 						return err | ||||||
|  | @ -215,7 +217,9 @@ func (s *statusDB) PutStatus(ctx context.Context, status *gtsmodel.Status) db.Er | ||||||
| 					Model(>smodel.StatusToTag{ | 					Model(>smodel.StatusToTag{ | ||||||
| 						StatusID: status.ID, | 						StatusID: status.ID, | ||||||
| 						TagID:    i, | 						TagID:    i, | ||||||
| 					}).Exec(ctx); err != nil { | 					}). | ||||||
|  | 					On("CONFLICT (?, ?) DO NOTHING", bun.Ident("status_id"), bun.Ident("tag_id")). | ||||||
|  | 					Exec(ctx); err != nil { | ||||||
| 					err = s.conn.ProcessError(err) | 					err = s.conn.ProcessError(err) | ||||||
| 					if !errors.Is(err, db.ErrAlreadyExists) { | 					if !errors.Is(err, db.ErrAlreadyExists) { | ||||||
| 						return err | 						return err | ||||||
|  | @ -261,7 +265,9 @@ func (s *statusDB) UpdateStatus(ctx context.Context, status *gtsmodel.Status, co | ||||||
| 				Model(>smodel.StatusToEmoji{ | 				Model(>smodel.StatusToEmoji{ | ||||||
| 					StatusID: status.ID, | 					StatusID: status.ID, | ||||||
| 					EmojiID:  i, | 					EmojiID:  i, | ||||||
| 				}).Exec(ctx); err != nil { | 				}). | ||||||
|  | 				On("CONFLICT (?, ?) DO NOTHING", bun.Ident("status_id"), bun.Ident("emoji_id")). | ||||||
|  | 				Exec(ctx); err != nil { | ||||||
| 				err = s.conn.ProcessError(err) | 				err = s.conn.ProcessError(err) | ||||||
| 				if !errors.Is(err, db.ErrAlreadyExists) { | 				if !errors.Is(err, db.ErrAlreadyExists) { | ||||||
| 					return err | 					return err | ||||||
|  | @ -276,7 +282,9 @@ func (s *statusDB) UpdateStatus(ctx context.Context, status *gtsmodel.Status, co | ||||||
| 				Model(>smodel.StatusToTag{ | 				Model(>smodel.StatusToTag{ | ||||||
| 					StatusID: status.ID, | 					StatusID: status.ID, | ||||||
| 					TagID:    i, | 					TagID:    i, | ||||||
| 				}).Exec(ctx); err != nil { | 				}). | ||||||
|  | 				On("CONFLICT (?, ?) DO NOTHING", bun.Ident("status_id"), bun.Ident("tag_id")). | ||||||
|  | 				Exec(ctx); err != nil { | ||||||
| 				err = s.conn.ProcessError(err) | 				err = s.conn.ProcessError(err) | ||||||
| 				if !errors.Is(err, db.ErrAlreadyExists) { | 				if !errors.Is(err, db.ErrAlreadyExists) { | ||||||
| 					return err | 					return err | ||||||
|  | @ -300,7 +308,7 @@ func (s *statusDB) UpdateStatus(ctx context.Context, status *gtsmodel.Status, co | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Finally, insert the status | 		// Finally, update the status | ||||||
| 		_, err := tx. | 		_, err := tx. | ||||||
| 			NewUpdate(). | 			NewUpdate(). | ||||||
| 			Model(status). | 			Model(status). | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/stretchr/testify/suite" | 	"github.com/stretchr/testify/suite" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type StatusTestSuite struct { | type StatusTestSuite struct { | ||||||
|  | @ -176,7 +177,10 @@ func (suite *StatusTestSuite) TestGetStatusChildren() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *StatusTestSuite) TestDeleteStatus() { | func (suite *StatusTestSuite) TestDeleteStatus() { | ||||||
| 	targetStatus := suite.testStatuses["admin_account_status_1"] | 	// Take a copy of the status. | ||||||
|  | 	targetStatus := >smodel.Status{} | ||||||
|  | 	*targetStatus = *suite.testStatuses["admin_account_status_1"] | ||||||
|  | 
 | ||||||
| 	err := suite.db.DeleteStatusByID(context.Background(), targetStatus.ID) | 	err := suite.db.DeleteStatusByID(context.Background(), targetStatus.ID) | ||||||
| 	suite.NoError(err) | 	suite.NoError(err) | ||||||
| 
 | 
 | ||||||
|  | @ -184,6 +188,31 @@ func (suite *StatusTestSuite) TestDeleteStatus() { | ||||||
| 	suite.ErrorIs(err, db.ErrNoEntries) | 	suite.ErrorIs(err, db.ErrNoEntries) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // This test was added specifically to ensure that Postgres wasn't getting upset | ||||||
|  | // about trying to use a transaction in which an error has already occurred, which | ||||||
|  | // was previously leading to errors like 'current transaction is aborted, commands | ||||||
|  | // ignored until end of transaction block' when updating a status that already had | ||||||
|  | // emojis or tags set on it. | ||||||
|  | // | ||||||
|  | // To run this test for postgres specifically, start a postgres container on localhost | ||||||
|  | // and then run: | ||||||
|  | // | ||||||
|  | // GTS_DB_TYPE=postgres GTS_DB_ADDRESS=localhost go test ./internal/db/bundb -run '^TestStatusTestSuite$' -testify.m '^(TestUpdateStatus)$' github.com/superseriousbusiness/gotosocial/internal/db/bundb | ||||||
|  | func (suite *StatusTestSuite) TestUpdateStatus() { | ||||||
|  | 	// Take a copy of the status. | ||||||
|  | 	targetStatus := >smodel.Status{} | ||||||
|  | 	*targetStatus = *suite.testStatuses["admin_account_status_1"] | ||||||
|  | 
 | ||||||
|  | 	targetStatus.PinnedAt = time.Time{} | ||||||
|  | 
 | ||||||
|  | 	err := suite.db.UpdateStatus(context.Background(), targetStatus, "pinned_at") | ||||||
|  | 	suite.NoError(err) | ||||||
|  | 
 | ||||||
|  | 	updated, err := suite.db.GetStatusByID(context.Background(), targetStatus.ID) | ||||||
|  | 	suite.NoError(err) | ||||||
|  | 	suite.True(updated.PinnedAt.IsZero()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestStatusTestSuite(t *testing.T) { | func TestStatusTestSuite(t *testing.T) { | ||||||
| 	suite.Run(t, new(StatusTestSuite)) | 	suite.Run(t, new(StatusTestSuite)) | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue