mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 07:22:24 -05:00 
			
		
		
		
	[bugfix] Don't copy ptr fields in caches (#2386)
This commit is contained in:
		
					parent
					
						
							
								0bb9b72334
							
						
					
				
			
			
				commit
				
					
						33ee61575f
					
				
			
		
					 12 changed files with 469 additions and 109 deletions
				
			
		
							
								
								
									
										329
									
								
								internal/cache/gts.go
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										329
									
								
								internal/cache/gts.go
									
										
									
									
										vendored
									
									
								
							|  | @ -306,6 +306,20 @@ func (c *GTSCaches) initAccount() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(a1 *gtsmodel.Account) *gtsmodel.Account { | ||||||
|  | 		a2 := new(gtsmodel.Account) | ||||||
|  | 		*a2 = *a1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/account.go. | ||||||
|  | 		a2.AvatarMediaAttachment = nil | ||||||
|  | 		a2.HeaderMediaAttachment = nil | ||||||
|  | 		a2.Emojis = nil | ||||||
|  | 
 | ||||||
|  | 		return a2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.account = result.New([]result.Lookup{ | 	c.account = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "URI"}, | 		{Name: "URI"}, | ||||||
|  | @ -316,11 +330,7 @@ func (c *GTSCaches) initAccount() { | ||||||
| 		{Name: "OutboxURI"}, | 		{Name: "OutboxURI"}, | ||||||
| 		{Name: "FollowersURI"}, | 		{Name: "FollowersURI"}, | ||||||
| 		{Name: "FollowingURI"}, | 		{Name: "FollowingURI"}, | ||||||
| 	}, func(a1 *gtsmodel.Account) *gtsmodel.Account { | 	}, copyF, cap) | ||||||
| 		a2 := new(gtsmodel.Account) |  | ||||||
| 		*a2 = *a1 |  | ||||||
| 		return a2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.account.IgnoreErrors(ignoreErrors) | 	c.account.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -334,14 +344,23 @@ func (c *GTSCaches) initAccountNote() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(n1 *gtsmodel.AccountNote) *gtsmodel.AccountNote { | ||||||
|  | 		n2 := new(gtsmodel.AccountNote) | ||||||
|  | 		*n2 = *n1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/relationship_note.go. | ||||||
|  | 		n2.Account = nil | ||||||
|  | 		n2.TargetAccount = nil | ||||||
|  | 
 | ||||||
|  | 		return n2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.accountNote = result.New([]result.Lookup{ | 	c.accountNote = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "AccountID.TargetAccountID"}, | 		{Name: "AccountID.TargetAccountID"}, | ||||||
| 	}, func(n1 *gtsmodel.AccountNote) *gtsmodel.AccountNote { | 	}, copyF, cap) | ||||||
| 		n2 := new(gtsmodel.AccountNote) |  | ||||||
| 		*n2 = *n1 |  | ||||||
| 		return n2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.accountNote.IgnoreErrors(ignoreErrors) | 	c.accountNote.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -376,17 +395,26 @@ func (c *GTSCaches) initBlock() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(b1 *gtsmodel.Block) *gtsmodel.Block { | ||||||
|  | 		b2 := new(gtsmodel.Block) | ||||||
|  | 		*b2 = *b1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/relationship_block.go. | ||||||
|  | 		b2.Account = nil | ||||||
|  | 		b2.TargetAccount = nil | ||||||
|  | 
 | ||||||
|  | 		return b2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.block = result.New([]result.Lookup{ | 	c.block = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "URI"}, | 		{Name: "URI"}, | ||||||
| 		{Name: "AccountID.TargetAccountID"}, | 		{Name: "AccountID.TargetAccountID"}, | ||||||
| 		{Name: "AccountID", Multi: true}, | 		{Name: "AccountID", Multi: true}, | ||||||
| 		{Name: "TargetAccountID", Multi: true}, | 		{Name: "TargetAccountID", Multi: true}, | ||||||
| 	}, func(b1 *gtsmodel.Block) *gtsmodel.Block { | 	}, copyF, cap) | ||||||
| 		b2 := new(gtsmodel.Block) |  | ||||||
| 		*b2 = *b1 |  | ||||||
| 		return b2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.block.IgnoreErrors(ignoreErrors) | 	c.block.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -436,17 +464,25 @@ func (c *GTSCaches) initEmoji() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(e1 *gtsmodel.Emoji) *gtsmodel.Emoji { | ||||||
|  | 		e2 := new(gtsmodel.Emoji) | ||||||
|  | 		*e2 = *e1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/emoji.go. | ||||||
|  | 		e2.Category = nil | ||||||
|  | 
 | ||||||
|  | 		return e2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.emoji = result.New([]result.Lookup{ | 	c.emoji = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "URI"}, | 		{Name: "URI"}, | ||||||
| 		{Name: "Shortcode.Domain", AllowZero: true /* domain can be zero i.e. "" */}, | 		{Name: "Shortcode.Domain", AllowZero: true /* domain can be zero i.e. "" */}, | ||||||
| 		{Name: "ImageStaticURL"}, | 		{Name: "ImageStaticURL"}, | ||||||
| 		{Name: "CategoryID", Multi: true}, | 		{Name: "CategoryID", Multi: true}, | ||||||
| 	}, func(e1 *gtsmodel.Emoji) *gtsmodel.Emoji { | 	}, copyF, cap) | ||||||
| 		e2 := new(gtsmodel.Emoji) |  | ||||||
| 		*e2 = *e1 |  | ||||||
| 		return e2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.emoji.IgnoreErrors(ignoreErrors) | 	c.emoji.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -481,17 +517,26 @@ func (c *GTSCaches) initFollow() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(f1 *gtsmodel.Follow) *gtsmodel.Follow { | ||||||
|  | 		f2 := new(gtsmodel.Follow) | ||||||
|  | 		*f2 = *f1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/relationship_follow.go. | ||||||
|  | 		f2.Account = nil | ||||||
|  | 		f2.TargetAccount = nil | ||||||
|  | 
 | ||||||
|  | 		return f2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.follow = result.New([]result.Lookup{ | 	c.follow = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "URI"}, | 		{Name: "URI"}, | ||||||
| 		{Name: "AccountID.TargetAccountID"}, | 		{Name: "AccountID.TargetAccountID"}, | ||||||
| 		{Name: "AccountID", Multi: true}, | 		{Name: "AccountID", Multi: true}, | ||||||
| 		{Name: "TargetAccountID", Multi: true}, | 		{Name: "TargetAccountID", Multi: true}, | ||||||
| 	}, func(f1 *gtsmodel.Follow) *gtsmodel.Follow { | 	}, copyF, cap) | ||||||
| 		f2 := new(gtsmodel.Follow) |  | ||||||
| 		*f2 = *f1 |  | ||||||
| 		return f2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.follow.IgnoreErrors(ignoreErrors) | 	c.follow.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -519,17 +564,26 @@ func (c *GTSCaches) initFollowRequest() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(f1 *gtsmodel.FollowRequest) *gtsmodel.FollowRequest { | ||||||
|  | 		f2 := new(gtsmodel.FollowRequest) | ||||||
|  | 		*f2 = *f1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/relationship_follow_req.go. | ||||||
|  | 		f2.Account = nil | ||||||
|  | 		f2.TargetAccount = nil | ||||||
|  | 
 | ||||||
|  | 		return f2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.followRequest = result.New([]result.Lookup{ | 	c.followRequest = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "URI"}, | 		{Name: "URI"}, | ||||||
| 		{Name: "AccountID.TargetAccountID"}, | 		{Name: "AccountID.TargetAccountID"}, | ||||||
| 		{Name: "AccountID", Multi: true}, | 		{Name: "AccountID", Multi: true}, | ||||||
| 		{Name: "TargetAccountID", Multi: true}, | 		{Name: "TargetAccountID", Multi: true}, | ||||||
| 	}, func(f1 *gtsmodel.FollowRequest) *gtsmodel.FollowRequest { | 	}, copyF, cap) | ||||||
| 		f2 := new(gtsmodel.FollowRequest) |  | ||||||
| 		*f2 = *f1 |  | ||||||
| 		return f2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.followRequest.IgnoreErrors(ignoreErrors) | 	c.followRequest.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -571,14 +625,23 @@ func (c *GTSCaches) initInstance() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(i1 *gtsmodel.Instance) *gtsmodel.Instance { | ||||||
|  | 		i2 := new(gtsmodel.Instance) | ||||||
|  | 		*i2 = *i1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/instance.go. | ||||||
|  | 		i2.DomainBlock = nil | ||||||
|  | 		i2.ContactAccount = nil | ||||||
|  | 
 | ||||||
|  | 		return i1 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.instance = result.New([]result.Lookup{ | 	c.instance = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "Domain"}, | 		{Name: "Domain"}, | ||||||
| 	}, func(i1 *gtsmodel.Instance) *gtsmodel.Instance { | 	}, copyF, cap) | ||||||
| 		i2 := new(gtsmodel.Instance) |  | ||||||
| 		*i2 = *i1 |  | ||||||
| 		return i1 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.instance.IgnoreErrors(ignoreErrors) | 	c.instance.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -592,13 +655,22 @@ func (c *GTSCaches) initList() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
| 	c.list = result.New([]result.Lookup{ | 	copyF := func(l1 *gtsmodel.List) *gtsmodel.List { | ||||||
| 		{Name: "ID"}, |  | ||||||
| 	}, func(l1 *gtsmodel.List) *gtsmodel.List { |  | ||||||
| 		l2 := new(gtsmodel.List) | 		l2 := new(gtsmodel.List) | ||||||
| 		*l2 = *l1 | 		*l2 = *l1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/list.go. | ||||||
|  | 		l2.Account = nil | ||||||
|  | 		l2.ListEntries = nil | ||||||
|  | 
 | ||||||
| 		return l2 | 		return l2 | ||||||
| 	}, cap) | 	} | ||||||
|  | 
 | ||||||
|  | 	c.list = result.New([]result.Lookup{ | ||||||
|  | 		{Name: "ID"}, | ||||||
|  | 	}, copyF, cap) | ||||||
| 
 | 
 | ||||||
| 	c.list.IgnoreErrors(ignoreErrors) | 	c.list.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -612,15 +684,23 @@ func (c *GTSCaches) initListEntry() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(l1 *gtsmodel.ListEntry) *gtsmodel.ListEntry { | ||||||
|  | 		l2 := new(gtsmodel.ListEntry) | ||||||
|  | 		*l2 = *l1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/list.go. | ||||||
|  | 		l2.Follow = nil | ||||||
|  | 
 | ||||||
|  | 		return l2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.listEntry = result.New([]result.Lookup{ | 	c.listEntry = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "ListID", Multi: true}, | 		{Name: "ListID", Multi: true}, | ||||||
| 		{Name: "FollowID", Multi: true}, | 		{Name: "FollowID", Multi: true}, | ||||||
| 	}, func(l1 *gtsmodel.ListEntry) *gtsmodel.ListEntry { | 	}, copyF, cap) | ||||||
| 		l2 := new(gtsmodel.ListEntry) |  | ||||||
| 		*l2 = *l1 |  | ||||||
| 		return l2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.listEntry.IgnoreErrors(ignoreErrors) | 	c.listEntry.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -674,13 +754,23 @@ func (c *GTSCaches) initMention() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
| 	c.mention = result.New([]result.Lookup{ | 	copyF := func(m1 *gtsmodel.Mention) *gtsmodel.Mention { | ||||||
| 		{Name: "ID"}, |  | ||||||
| 	}, func(m1 *gtsmodel.Mention) *gtsmodel.Mention { |  | ||||||
| 		m2 := new(gtsmodel.Mention) | 		m2 := new(gtsmodel.Mention) | ||||||
| 		*m2 = *m1 | 		*m2 = *m1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/mention.go. | ||||||
|  | 		m2.Status = nil | ||||||
|  | 		m2.OriginAccount = nil | ||||||
|  | 		m2.TargetAccount = nil | ||||||
|  | 
 | ||||||
| 		return m2 | 		return m2 | ||||||
| 	}, cap) | 	} | ||||||
|  | 
 | ||||||
|  | 	c.mention = result.New([]result.Lookup{ | ||||||
|  | 		{Name: "ID"}, | ||||||
|  | 	}, copyF, cap) | ||||||
| 
 | 
 | ||||||
| 	c.mention.IgnoreErrors(ignoreErrors) | 	c.mention.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -694,14 +784,24 @@ func (c *GTSCaches) initNotification() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(n1 *gtsmodel.Notification) *gtsmodel.Notification { | ||||||
|  | 		n2 := new(gtsmodel.Notification) | ||||||
|  | 		*n2 = *n1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/notification.go. | ||||||
|  | 		n2.Status = nil | ||||||
|  | 		n2.OriginAccount = nil | ||||||
|  | 		n2.TargetAccount = nil | ||||||
|  | 
 | ||||||
|  | 		return n2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.notification = result.New([]result.Lookup{ | 	c.notification = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "NotificationType.TargetAccountID.OriginAccountID.StatusID"}, | 		{Name: "NotificationType.TargetAccountID.OriginAccountID.StatusID"}, | ||||||
| 	}, func(n1 *gtsmodel.Notification) *gtsmodel.Notification { | 	}, copyF, cap) | ||||||
| 		n2 := new(gtsmodel.Notification) |  | ||||||
| 		*n2 = *n1 |  | ||||||
| 		return n2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.notification.IgnoreErrors(ignoreErrors) | 	c.notification.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -715,14 +815,22 @@ func (c *GTSCaches) initPoll() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(p1 *gtsmodel.Poll) *gtsmodel.Poll { | ||||||
|  | 		p2 := new(gtsmodel.Poll) | ||||||
|  | 		*p2 = *p1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/poll.go. | ||||||
|  | 		p2.Status = nil | ||||||
|  | 
 | ||||||
|  | 		return p2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.poll = result.New([]result.Lookup{ | 	c.poll = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "StatusID"}, | 		{Name: "StatusID"}, | ||||||
| 	}, func(p1 *gtsmodel.Poll) *gtsmodel.Poll { | 	}, copyF, cap) | ||||||
| 		p2 := new(gtsmodel.Poll) |  | ||||||
| 		*p2 = *p1 |  | ||||||
| 		return p2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.poll.IgnoreErrors(ignoreErrors) | 	c.poll.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -736,15 +844,24 @@ func (c *GTSCaches) initPollVote() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(v1 *gtsmodel.PollVote) *gtsmodel.PollVote { | ||||||
|  | 		v2 := new(gtsmodel.PollVote) | ||||||
|  | 		*v2 = *v1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/poll.go. | ||||||
|  | 		v2.Account = nil | ||||||
|  | 		v2.Poll = nil | ||||||
|  | 
 | ||||||
|  | 		return v2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.pollVote = result.New([]result.Lookup{ | 	c.pollVote = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "PollID.AccountID"}, | 		{Name: "PollID.AccountID"}, | ||||||
| 		{Name: "PollID", Multi: true}, | 		{Name: "PollID", Multi: true}, | ||||||
| 	}, func(v1 *gtsmodel.PollVote) *gtsmodel.PollVote { | 	}, copyF, cap) | ||||||
| 		v2 := new(gtsmodel.PollVote) |  | ||||||
| 		*v2 = *v1 |  | ||||||
| 		return v2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.pollVote.IgnoreErrors(ignoreErrors) | 	c.pollVote.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -772,13 +889,25 @@ func (c *GTSCaches) initReport() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
| 	c.report = result.New([]result.Lookup{ | 	copyF := func(r1 *gtsmodel.Report) *gtsmodel.Report { | ||||||
| 		{Name: "ID"}, |  | ||||||
| 	}, func(r1 *gtsmodel.Report) *gtsmodel.Report { |  | ||||||
| 		r2 := new(gtsmodel.Report) | 		r2 := new(gtsmodel.Report) | ||||||
| 		*r2 = *r1 | 		*r2 = *r1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/report.go. | ||||||
|  | 		r2.Account = nil | ||||||
|  | 		r2.TargetAccount = nil | ||||||
|  | 		r2.Statuses = nil | ||||||
|  | 		r2.Rules = nil | ||||||
|  | 		r2.ActionTakenByAccount = nil | ||||||
|  | 
 | ||||||
| 		return r2 | 		return r2 | ||||||
| 	}, cap) | 	} | ||||||
|  | 
 | ||||||
|  | 	c.report = result.New([]result.Lookup{ | ||||||
|  | 		{Name: "ID"}, | ||||||
|  | 	}, copyF, cap) | ||||||
| 
 | 
 | ||||||
| 	c.report.IgnoreErrors(ignoreErrors) | 	c.report.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -792,17 +921,35 @@ func (c *GTSCaches) initStatus() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(s1 *gtsmodel.Status) *gtsmodel.Status { | ||||||
|  | 		s2 := new(gtsmodel.Status) | ||||||
|  | 		*s2 = *s1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/status.go. | ||||||
|  | 		s2.Account = nil | ||||||
|  | 		s2.InReplyTo = nil | ||||||
|  | 		s2.InReplyToAccount = nil | ||||||
|  | 		s2.BoostOf = nil | ||||||
|  | 		s2.BoostOfAccount = nil | ||||||
|  | 		s2.Poll = nil | ||||||
|  | 		s2.Attachments = nil | ||||||
|  | 		s2.Tags = nil | ||||||
|  | 		s2.Mentions = nil | ||||||
|  | 		s2.Emojis = nil | ||||||
|  | 		s2.CreatedWithApplication = nil | ||||||
|  | 
 | ||||||
|  | 		return s2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.status = result.New([]result.Lookup{ | 	c.status = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "URI"}, | 		{Name: "URI"}, | ||||||
| 		{Name: "URL"}, | 		{Name: "URL"}, | ||||||
| 		{Name: "BoostOfID.AccountID"}, | 		{Name: "BoostOfID.AccountID"}, | ||||||
| 		{Name: "ThreadID", Multi: true}, | 		{Name: "ThreadID", Multi: true}, | ||||||
| 	}, func(s1 *gtsmodel.Status) *gtsmodel.Status { | 	}, copyF, cap) | ||||||
| 		s2 := new(gtsmodel.Status) |  | ||||||
| 		*s2 = *s1 |  | ||||||
| 		return s2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.status.IgnoreErrors(ignoreErrors) | 	c.status.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -816,15 +963,25 @@ func (c *GTSCaches) initStatusFave() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(f1 *gtsmodel.StatusFave) *gtsmodel.StatusFave { | ||||||
|  | 		f2 := new(gtsmodel.StatusFave) | ||||||
|  | 		*f2 = *f1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/statusfave.go. | ||||||
|  | 		f2.Account = nil | ||||||
|  | 		f2.TargetAccount = nil | ||||||
|  | 		f2.Status = nil | ||||||
|  | 
 | ||||||
|  | 		return f2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.statusFave = result.New([]result.Lookup{ | 	c.statusFave = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "AccountID.StatusID"}, | 		{Name: "AccountID.StatusID"}, | ||||||
| 		{Name: "StatusID", Multi: true}, | 		{Name: "StatusID", Multi: true}, | ||||||
| 	}, func(f1 *gtsmodel.StatusFave) *gtsmodel.StatusFave { | 	}, copyF, cap) | ||||||
| 		f2 := new(gtsmodel.StatusFave) |  | ||||||
| 		*f2 = *f1 |  | ||||||
| 		return f2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.statusFave.IgnoreErrors(ignoreErrors) | 	c.statusFave.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  | @ -916,17 +1073,25 @@ func (c *GTSCaches) initUser() { | ||||||
| 
 | 
 | ||||||
| 	log.Infof(nil, "cache size = %d", cap) | 	log.Infof(nil, "cache size = %d", cap) | ||||||
| 
 | 
 | ||||||
|  | 	copyF := func(u1 *gtsmodel.User) *gtsmodel.User { | ||||||
|  | 		u2 := new(gtsmodel.User) | ||||||
|  | 		*u2 = *u1 | ||||||
|  | 
 | ||||||
|  | 		// Don't include ptr fields that | ||||||
|  | 		// will be populated separately. | ||||||
|  | 		// See internal/db/bundb/user.go. | ||||||
|  | 		u2.Account = nil | ||||||
|  | 
 | ||||||
|  | 		return u2 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	c.user = result.New([]result.Lookup{ | 	c.user = result.New([]result.Lookup{ | ||||||
| 		{Name: "ID"}, | 		{Name: "ID"}, | ||||||
| 		{Name: "AccountID"}, | 		{Name: "AccountID"}, | ||||||
| 		{Name: "Email"}, | 		{Name: "Email"}, | ||||||
| 		{Name: "ConfirmationToken"}, | 		{Name: "ConfirmationToken"}, | ||||||
| 		{Name: "ExternalID"}, | 		{Name: "ExternalID"}, | ||||||
| 	}, func(u1 *gtsmodel.User) *gtsmodel.User { | 	}, copyF, cap) | ||||||
| 		u2 := new(gtsmodel.User) |  | ||||||
| 		*u2 = *u1 |  | ||||||
| 		return u2 |  | ||||||
| 	}, cap) |  | ||||||
| 
 | 
 | ||||||
| 	c.user.IgnoreErrors(ignoreErrors) | 	c.user.IgnoreErrors(ignoreErrors) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/log" | 	"github.com/superseriousbusiness/gotosocial/internal/log" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/state" | 	"github.com/superseriousbusiness/gotosocial/internal/state" | ||||||
|  | @ -548,6 +549,25 @@ func (e *emojiDB) getEmoji(ctx context.Context, lookup string, dbQuery func(*gts | ||||||
| 	return emoji, nil | 	return emoji, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (e *emojiDB) PopulateEmoji(ctx context.Context, emoji *gtsmodel.Emoji) error { | ||||||
|  | 	var ( | ||||||
|  | 		errs = gtserror.NewMultiError(1) | ||||||
|  | 		err  error | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	if emoji.CategoryID != "" && emoji.Category == nil { | ||||||
|  | 		emoji.Category, err = e.GetEmojiCategory( | ||||||
|  | 			ctx, // these are already barebones | ||||||
|  | 			emoji.CategoryID, | ||||||
|  | 		) | ||||||
|  | 		if err != nil { | ||||||
|  | 			errs.Appendf("error populating emoji category: %w", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return errs.Combine() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (e *emojiDB) GetEmojisByIDs(ctx context.Context, emojiIDs []string) ([]*gtsmodel.Emoji, error) { | func (e *emojiDB) GetEmojisByIDs(ctx context.Context, emojiIDs []string) ([]*gtsmodel.Emoji, error) { | ||||||
| 	if len(emojiIDs) == 0 { | 	if len(emojiIDs) == 0 { | ||||||
| 		return nil, db.ErrNoEntries | 		return nil, db.ErrNoEntries | ||||||
|  |  | ||||||
|  | @ -173,14 +173,14 @@ func (i *instanceDB) getInstance(ctx context.Context, lookup string, dbQuery fun | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Further populate the instance fields where applicable. | 	// Further populate the instance fields where applicable. | ||||||
| 	if err := i.populateInstance(ctx, instance); err != nil { | 	if err := i.PopulateInstance(ctx, instance); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return instance, nil | 	return instance, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (i *instanceDB) populateInstance(ctx context.Context, instance *gtsmodel.Instance) error { | func (i *instanceDB) PopulateInstance(ctx context.Context, instance *gtsmodel.Instance) error { | ||||||
| 	var ( | 	var ( | ||||||
| 		err  error | 		err  error | ||||||
| 		errs = gtserror.NewMultiError(2) | 		errs = gtserror.NewMultiError(2) | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/db" | 	"github.com/superseriousbusiness/gotosocial/internal/db" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/id" | 	"github.com/superseriousbusiness/gotosocial/internal/id" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/log" | 	"github.com/superseriousbusiness/gotosocial/internal/log" | ||||||
|  | @ -57,7 +58,7 @@ func (n *notificationDB) GetNotification( | ||||||
| 	originAccountID string, | 	originAccountID string, | ||||||
| 	statusID string, | 	statusID string, | ||||||
| ) (*gtsmodel.Notification, error) { | ) (*gtsmodel.Notification, error) { | ||||||
| 	return n.state.Caches.GTS.Notification().Load("NotificationType.TargetAccountID.OriginAccountID.StatusID", func() (*gtsmodel.Notification, error) { | 	notif, err := n.state.Caches.GTS.Notification().Load("NotificationType.TargetAccountID.OriginAccountID.StatusID", func() (*gtsmodel.Notification, error) { | ||||||
| 		var notif gtsmodel.Notification | 		var notif gtsmodel.Notification | ||||||
| 
 | 
 | ||||||
| 		q := n.db.NewSelect(). | 		q := n.db.NewSelect(). | ||||||
|  | @ -73,6 +74,60 @@ func (n *notificationDB) GetNotification( | ||||||
| 
 | 
 | ||||||
| 		return ¬if, nil | 		return ¬if, nil | ||||||
| 	}, notificationType, targetAccountID, originAccountID, statusID) | 	}, notificationType, targetAccountID, originAccountID, statusID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if gtscontext.Barebones(ctx) { | ||||||
|  | 		// no need to fully populate. | ||||||
|  | 		return notif, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Further populate the notif fields where applicable. | ||||||
|  | 	if err := n.PopulateNotification(ctx, notif); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return notif, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (n *notificationDB) PopulateNotification(ctx context.Context, notif *gtsmodel.Notification) error { | ||||||
|  | 	var ( | ||||||
|  | 		errs = gtserror.NewMultiError(2) | ||||||
|  | 		err  error | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	if notif.TargetAccount == nil { | ||||||
|  | 		notif.TargetAccount, err = n.state.DB.GetAccountByID( | ||||||
|  | 			gtscontext.SetBarebones(ctx), | ||||||
|  | 			notif.TargetAccountID, | ||||||
|  | 		) | ||||||
|  | 		if err != nil { | ||||||
|  | 			errs.Appendf("error populating notif target account: %w", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if notif.OriginAccount == nil { | ||||||
|  | 		notif.OriginAccount, err = n.state.DB.GetAccountByID( | ||||||
|  | 			gtscontext.SetBarebones(ctx), | ||||||
|  | 			notif.OriginAccountID, | ||||||
|  | 		) | ||||||
|  | 		if err != nil { | ||||||
|  | 			errs.Appendf("error populating notif origin account: %w", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if notif.StatusID != "" && notif.Status == nil { | ||||||
|  | 		notif.Status, err = n.state.DB.GetStatusByID( | ||||||
|  | 			gtscontext.SetBarebones(ctx), | ||||||
|  | 			notif.StatusID, | ||||||
|  | 		) | ||||||
|  | 		if err != nil { | ||||||
|  | 			errs.Appendf("error populating notif status: %w", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return errs.Combine() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *notificationDB) GetAccountNotifications( | func (n *notificationDB) GetAccountNotifications( | ||||||
|  |  | ||||||
|  | @ -19,10 +19,10 @@ package bundb | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" |  | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | ||||||
|  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | ||||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||||
| 	"github.com/uptrace/bun" | 	"github.com/uptrace/bun" | ||||||
| ) | ) | ||||||
|  | @ -64,25 +64,43 @@ func (r *relationshipDB) getNote(ctx context.Context, lookup string, dbQuery fun | ||||||
| 		return note, nil | 		return note, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Set the note source account | 	// Further populate the account fields where applicable. | ||||||
|  | 	if err := r.PopulateNote(ctx, note); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return note, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *relationshipDB) PopulateNote(ctx context.Context, note *gtsmodel.AccountNote) error { | ||||||
|  | 	var ( | ||||||
|  | 		errs = gtserror.NewMultiError(2) | ||||||
|  | 		err  error | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	// Ensure note source account set. | ||||||
|  | 	if note.Account == nil { | ||||||
| 		note.Account, err = r.state.DB.GetAccountByID( | 		note.Account, err = r.state.DB.GetAccountByID( | ||||||
| 			gtscontext.SetBarebones(ctx), | 			gtscontext.SetBarebones(ctx), | ||||||
| 			note.AccountID, | 			note.AccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 		return nil, fmt.Errorf("error getting note source account: %w", err) | 			errs.Appendf("error populating note source account: %w", err) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Set the note target account | 	// Ensure note target account set. | ||||||
|  | 	if note.TargetAccount == nil { | ||||||
| 		note.TargetAccount, err = r.state.DB.GetAccountByID( | 		note.TargetAccount, err = r.state.DB.GetAccountByID( | ||||||
| 			gtscontext.SetBarebones(ctx), | 			gtscontext.SetBarebones(ctx), | ||||||
| 			note.TargetAccountID, | 			note.TargetAccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 		return nil, fmt.Errorf("error getting note target account: %w", err) | 			errs.Appendf("error populating note target account: %w", err) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return note, nil | 	return errs.Combine() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (r *relationshipDB) PutNote(ctx context.Context, note *gtsmodel.AccountNote) error { | func (r *relationshipDB) PutNote(ctx context.Context, note *gtsmodel.AccountNote) error { | ||||||
|  |  | ||||||
|  | @ -224,6 +224,51 @@ func (suite *StatusTestSuite) TestUpdateStatus() { | ||||||
| 	suite.True(updated.PinnedAt.IsZero()) | 	suite.True(updated.PinnedAt.IsZero()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (suite *StatusTestSuite) TestPutPopulatedStatus() { | ||||||
|  | 	ctx := context.Background() | ||||||
|  | 
 | ||||||
|  | 	targetStatus := >smodel.Status{} | ||||||
|  | 	*targetStatus = *suite.testStatuses["admin_account_status_1"] | ||||||
|  | 
 | ||||||
|  | 	// Populate fields on the target status. | ||||||
|  | 	if err := suite.db.PopulateStatus(ctx, targetStatus); err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Delete it from the database. | ||||||
|  | 	if err := suite.db.DeleteStatusByID(ctx, targetStatus.ID); err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Reinsert the populated version | ||||||
|  | 	// so that it becomes cached. | ||||||
|  | 	if err := suite.db.PutStatus(ctx, targetStatus); err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Update the status owner's | ||||||
|  | 	// account with a new bio. | ||||||
|  | 	account := >smodel.Account{} | ||||||
|  | 	*account = *targetStatus.Account | ||||||
|  | 	account.Note = "new note for this test" | ||||||
|  | 	if err := suite.db.UpdateAccount(ctx, account, "note"); err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dbStatus, err := suite.db.GetStatusByID(ctx, targetStatus.ID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		suite.FailNow(err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Account note should be updated, | ||||||
|  | 	// even though we stored this | ||||||
|  | 	// status with the old note. | ||||||
|  | 	suite.Equal( | ||||||
|  | 		"new note for this test", | ||||||
|  | 		dbStatus.Account.Note, | ||||||
|  | 	) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestStatusTestSuite(t *testing.T) { | func TestStatusTestSuite(t *testing.T) { | ||||||
| 	suite.Run(t, new(StatusTestSuite)) | 	suite.Run(t, new(StatusTestSuite)) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -130,16 +130,37 @@ func (u *userDB) getUser(ctx context.Context, lookup string, dbQuery func(*gtsmo | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if gtscontext.Barebones(ctx) { | ||||||
|  | 		// Return without populating. | ||||||
|  | 		return user, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := u.PopulateUser(ctx, user); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return user, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // PopulateUser ensures that the user's struct fields are populated. | ||||||
|  | func (u *userDB) PopulateUser(ctx context.Context, user *gtsmodel.User) error { | ||||||
|  | 	var ( | ||||||
|  | 		errs = gtserror.NewMultiError(1) | ||||||
|  | 		err  error | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	if user.Account == nil { | ||||||
| 		// Fetch the related account model for this user. | 		// Fetch the related account model for this user. | ||||||
| 		user.Account, err = u.state.DB.GetAccountByID( | 		user.Account, err = u.state.DB.GetAccountByID( | ||||||
| 			gtscontext.SetBarebones(ctx), | 			gtscontext.SetBarebones(ctx), | ||||||
| 			user.AccountID, | 			user.AccountID, | ||||||
| 		) | 		) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 		return nil, gtserror.Newf("error populating user account: %w", err) | 			errs.Appendf("error populating user account: %w", err) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return user, nil | 	return errs.Combine() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (u *userDB) GetAllUsers(ctx context.Context) ([]*gtsmodel.User, error) { | func (u *userDB) GetAllUsers(ctx context.Context) ([]*gtsmodel.User, error) { | ||||||
|  |  | ||||||
|  | @ -32,13 +32,17 @@ const EmojiAllDomains string = "all" | ||||||
| type Emoji interface { | type Emoji interface { | ||||||
| 	// PutEmoji puts one emoji in the database. | 	// PutEmoji puts one emoji in the database. | ||||||
| 	PutEmoji(ctx context.Context, emoji *gtsmodel.Emoji) error | 	PutEmoji(ctx context.Context, emoji *gtsmodel.Emoji) error | ||||||
|  | 
 | ||||||
| 	// UpdateEmoji updates the given columns of one emoji. | 	// UpdateEmoji updates the given columns of one emoji. | ||||||
| 	// If no columns are specified, every column is updated. | 	// If no columns are specified, every column is updated. | ||||||
| 	UpdateEmoji(ctx context.Context, emoji *gtsmodel.Emoji, columns ...string) error | 	UpdateEmoji(ctx context.Context, emoji *gtsmodel.Emoji, columns ...string) error | ||||||
|  | 
 | ||||||
| 	// DeleteEmojiByID deletes one emoji by its database ID. | 	// DeleteEmojiByID deletes one emoji by its database ID. | ||||||
| 	DeleteEmojiByID(ctx context.Context, id string) error | 	DeleteEmojiByID(ctx context.Context, id string) error | ||||||
|  | 
 | ||||||
| 	// GetEmojisByIDs gets emojis for the given IDs. | 	// GetEmojisByIDs gets emojis for the given IDs. | ||||||
| 	GetEmojisByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Emoji, error) | 	GetEmojisByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Emoji, error) | ||||||
|  | 
 | ||||||
| 	// GetUseableEmojis gets all emojis which are useable by accounts on this instance. | 	// GetUseableEmojis gets all emojis which are useable by accounts on this instance. | ||||||
| 	GetUseableEmojis(ctx context.Context) ([]*gtsmodel.Emoji, error) | 	GetUseableEmojis(ctx context.Context) ([]*gtsmodel.Emoji, error) | ||||||
| 
 | 
 | ||||||
|  | @ -53,23 +57,35 @@ type Emoji interface { | ||||||
| 
 | 
 | ||||||
| 	// GetEmojisBy gets emojis based on given parameters. Useful for admin actions. | 	// GetEmojisBy gets emojis based on given parameters. Useful for admin actions. | ||||||
| 	GetEmojisBy(ctx context.Context, domain string, includeDisabled bool, includeEnabled bool, shortcode string, maxShortcodeDomain string, minShortcodeDomain string, limit int) ([]*gtsmodel.Emoji, error) | 	GetEmojisBy(ctx context.Context, domain string, includeDisabled bool, includeEnabled bool, shortcode string, maxShortcodeDomain string, minShortcodeDomain string, limit int) ([]*gtsmodel.Emoji, error) | ||||||
|  | 
 | ||||||
| 	// GetEmojiByID gets a specific emoji by its database ID. | 	// GetEmojiByID gets a specific emoji by its database ID. | ||||||
| 	GetEmojiByID(ctx context.Context, id string) (*gtsmodel.Emoji, error) | 	GetEmojiByID(ctx context.Context, id string) (*gtsmodel.Emoji, error) | ||||||
|  | 
 | ||||||
|  | 	// PopulateEmoji populates the struct pointers on the given emoji. | ||||||
|  | 	PopulateEmoji(ctx context.Context, emoji *gtsmodel.Emoji) error | ||||||
|  | 
 | ||||||
| 	// GetEmojiByShortcodeDomain gets an emoji based on its shortcode and domain. | 	// GetEmojiByShortcodeDomain gets an emoji based on its shortcode and domain. | ||||||
| 	// For local emoji, domain should be an empty string. | 	// For local emoji, domain should be an empty string. | ||||||
| 	GetEmojiByShortcodeDomain(ctx context.Context, shortcode string, domain string) (*gtsmodel.Emoji, error) | 	GetEmojiByShortcodeDomain(ctx context.Context, shortcode string, domain string) (*gtsmodel.Emoji, error) | ||||||
|  | 
 | ||||||
| 	// GetEmojiByURI returns one emoji based on its ActivityPub URI. | 	// GetEmojiByURI returns one emoji based on its ActivityPub URI. | ||||||
| 	GetEmojiByURI(ctx context.Context, uri string) (*gtsmodel.Emoji, error) | 	GetEmojiByURI(ctx context.Context, uri string) (*gtsmodel.Emoji, error) | ||||||
|  | 
 | ||||||
| 	// GetEmojiByStaticURL gets an emoji using the URL of the static version of the emoji image. | 	// GetEmojiByStaticURL gets an emoji using the URL of the static version of the emoji image. | ||||||
| 	GetEmojiByStaticURL(ctx context.Context, imageStaticURL string) (*gtsmodel.Emoji, error) | 	GetEmojiByStaticURL(ctx context.Context, imageStaticURL string) (*gtsmodel.Emoji, error) | ||||||
|  | 
 | ||||||
| 	// PutEmojiCategory puts one new emoji category in the database. | 	// PutEmojiCategory puts one new emoji category in the database. | ||||||
| 	PutEmojiCategory(ctx context.Context, emojiCategory *gtsmodel.EmojiCategory) error | 	PutEmojiCategory(ctx context.Context, emojiCategory *gtsmodel.EmojiCategory) error | ||||||
|  | 
 | ||||||
| 	// GetEmojiCategoriesByIDs gets emoji categories for given IDs. | 	// GetEmojiCategoriesByIDs gets emoji categories for given IDs. | ||||||
| 	GetEmojiCategoriesByIDs(ctx context.Context, ids []string) ([]*gtsmodel.EmojiCategory, error) | 	GetEmojiCategoriesByIDs(ctx context.Context, ids []string) ([]*gtsmodel.EmojiCategory, error) | ||||||
|  | 
 | ||||||
| 	// GetEmojiCategories gets a slice of the names of all existing emoji categories. | 	// GetEmojiCategories gets a slice of the names of all existing emoji categories. | ||||||
| 	GetEmojiCategories(ctx context.Context) ([]*gtsmodel.EmojiCategory, error) | 	GetEmojiCategories(ctx context.Context) ([]*gtsmodel.EmojiCategory, error) | ||||||
|  | 
 | ||||||
| 	// GetEmojiCategory gets one emoji category by its id. | 	// GetEmojiCategory gets one emoji category by its id. | ||||||
| 	GetEmojiCategory(ctx context.Context, id string) (*gtsmodel.EmojiCategory, error) | 	GetEmojiCategory(ctx context.Context, id string) (*gtsmodel.EmojiCategory, error) | ||||||
|  | 
 | ||||||
| 	// GetEmojiCategoryByName gets one emoji category by its name. | 	// GetEmojiCategoryByName gets one emoji category by its name. | ||||||
| 	GetEmojiCategoryByName(ctx context.Context, name string) (*gtsmodel.EmojiCategory, error) | 	GetEmojiCategoryByName(ctx context.Context, name string) (*gtsmodel.EmojiCategory, error) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -40,6 +40,9 @@ type Instance interface { | ||||||
| 	// GetInstanceByID returns the instance entry corresponding to the given id, if it exists. | 	// GetInstanceByID returns the instance entry corresponding to the given id, if it exists. | ||||||
| 	GetInstanceByID(ctx context.Context, id string) (*gtsmodel.Instance, error) | 	GetInstanceByID(ctx context.Context, id string) (*gtsmodel.Instance, error) | ||||||
| 
 | 
 | ||||||
|  | 	// PopulateInstance populates the struct pointers on the given instance. | ||||||
|  | 	PopulateInstance(ctx context.Context, instance *gtsmodel.Instance) error | ||||||
|  | 
 | ||||||
| 	// PutInstance inserts the given instance into the database. | 	// PutInstance inserts the given instance into the database. | ||||||
| 	PutInstance(ctx context.Context, instance *gtsmodel.Instance) error | 	PutInstance(ctx context.Context, instance *gtsmodel.Instance) error | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,6 +37,9 @@ type Notification interface { | ||||||
| 	// Since not all notifications are about a status, statusID can be an empty string. | 	// Since not all notifications are about a status, statusID can be an empty string. | ||||||
| 	GetNotification(ctx context.Context, notificationType gtsmodel.NotificationType, targetAccountID string, originAccountID string, statusID string) (*gtsmodel.Notification, error) | 	GetNotification(ctx context.Context, notificationType gtsmodel.NotificationType, targetAccountID string, originAccountID string, statusID string) (*gtsmodel.Notification, error) | ||||||
| 
 | 
 | ||||||
|  | 	// PopulateNotification ensures that the notification's struct fields are populated. | ||||||
|  | 	PopulateNotification(ctx context.Context, notif *gtsmodel.Notification) error | ||||||
|  | 
 | ||||||
| 	// PutNotification will insert the given notification into the database. | 	// PutNotification will insert the given notification into the database. | ||||||
| 	PutNotification(ctx context.Context, notif *gtsmodel.Notification) error | 	PutNotification(ctx context.Context, notif *gtsmodel.Notification) error | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -184,4 +184,7 @@ type Relationship interface { | ||||||
| 
 | 
 | ||||||
| 	// PutNote creates or updates a private note. | 	// PutNote creates or updates a private note. | ||||||
| 	PutNote(ctx context.Context, note *gtsmodel.AccountNote) error | 	PutNote(ctx context.Context, note *gtsmodel.AccountNote) error | ||||||
|  | 
 | ||||||
|  | 	// PopulateNote populates the struct pointers on the given note. | ||||||
|  | 	PopulateNote(ctx context.Context, note *gtsmodel.AccountNote) error | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -27,20 +27,31 @@ import ( | ||||||
| type User interface { | type User interface { | ||||||
| 	// GetAllUsers returns all local user accounts, or an error if something goes wrong. | 	// GetAllUsers returns all local user accounts, or an error if something goes wrong. | ||||||
| 	GetAllUsers(ctx context.Context) ([]*gtsmodel.User, error) | 	GetAllUsers(ctx context.Context) ([]*gtsmodel.User, error) | ||||||
|  | 
 | ||||||
| 	// GetUserByID returns one user with the given ID, or an error if something goes wrong. | 	// GetUserByID returns one user with the given ID, or an error if something goes wrong. | ||||||
| 	GetUserByID(ctx context.Context, id string) (*gtsmodel.User, error) | 	GetUserByID(ctx context.Context, id string) (*gtsmodel.User, error) | ||||||
|  | 
 | ||||||
| 	// GetUserByAccountID returns one user by its account ID, or an error if something goes wrong. | 	// GetUserByAccountID returns one user by its account ID, or an error if something goes wrong. | ||||||
| 	GetUserByAccountID(ctx context.Context, accountID string) (*gtsmodel.User, error) | 	GetUserByAccountID(ctx context.Context, accountID string) (*gtsmodel.User, error) | ||||||
|  | 
 | ||||||
| 	// GetUserByID returns one user with the given email address, or an error if something goes wrong. | 	// GetUserByID returns one user with the given email address, or an error if something goes wrong. | ||||||
| 	GetUserByEmailAddress(ctx context.Context, emailAddress string) (*gtsmodel.User, error) | 	GetUserByEmailAddress(ctx context.Context, emailAddress string) (*gtsmodel.User, error) | ||||||
|  | 
 | ||||||
| 	// GetUserByExternalID returns one user with the given external id, or an error if something goes wrong. | 	// GetUserByExternalID returns one user with the given external id, or an error if something goes wrong. | ||||||
| 	GetUserByExternalID(ctx context.Context, id string) (*gtsmodel.User, error) | 	GetUserByExternalID(ctx context.Context, id string) (*gtsmodel.User, error) | ||||||
|  | 
 | ||||||
| 	// GetUserByConfirmationToken returns one user by its confirmation token, or an error if something goes wrong. | 	// GetUserByConfirmationToken returns one user by its confirmation token, or an error if something goes wrong. | ||||||
| 	GetUserByConfirmationToken(ctx context.Context, confirmationToken string) (*gtsmodel.User, error) | 	GetUserByConfirmationToken(ctx context.Context, confirmationToken string) (*gtsmodel.User, error) | ||||||
|  | 
 | ||||||
|  | 	// PopulateUser populates the struct pointers on the given user. | ||||||
|  | 	PopulateUser(ctx context.Context, user *gtsmodel.User) error | ||||||
|  | 
 | ||||||
| 	// PutUser will attempt to place user in the database | 	// PutUser will attempt to place user in the database | ||||||
| 	PutUser(ctx context.Context, user *gtsmodel.User) error | 	PutUser(ctx context.Context, user *gtsmodel.User) error | ||||||
|  | 
 | ||||||
| 	// UpdateUser updates one user by its primary key, updating either only the specified columns, or all of them. | 	// UpdateUser updates one user by its primary key, updating either only the specified columns, or all of them. | ||||||
| 	UpdateUser(ctx context.Context, user *gtsmodel.User, columns ...string) error | 	UpdateUser(ctx context.Context, user *gtsmodel.User, columns ...string) error | ||||||
|  | 
 | ||||||
| 	// DeleteUserByID deletes one user by its ID. | 	// DeleteUserByID deletes one user by its ID. | ||||||
| 	DeleteUserByID(ctx context.Context, userID string) error | 	DeleteUserByID(ctx context.Context, userID string) error | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue