| 
									
										
										
										
											2023-03-12 16:00:57 +01:00
										 |  |  | // GoToSocial | 
					
						
							|  |  |  | // Copyright (C) GoToSocial Authors admin@gotosocial.org | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-or-later | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | // GNU Affero General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | package bundb | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	"slices" | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | 
					
						
							| 
									
										
										
										
											2023-11-27 16:39:44 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/id" | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/log" | 
					
						
							| 
									
										
										
										
											2022-12-08 17:35:14 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/state" | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/util" | 
					
						
							| 
									
										
										
										
											2022-10-08 13:50:48 +02:00
										 |  |  | 	"github.com/uptrace/bun" | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type notificationDB struct { | 
					
						
							| 
									
										
										
										
											2024-02-07 14:43:27 +00:00
										 |  |  | 	db    *bun.DB | 
					
						
							| 
									
										
										
										
											2022-12-08 17:35:14 +00:00
										 |  |  | 	state *state.State | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (n *notificationDB) GetNotificationByID(ctx context.Context, id string) (*gtsmodel.Notification, error) { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	return n.getNotification( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							|  |  |  | 		"ID", | 
					
						
							|  |  |  | 		func(notif *gtsmodel.Notification) error { | 
					
						
							|  |  |  | 			return n.db.NewSelect(). | 
					
						
							|  |  |  | 				Model(notif). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("id"), id). | 
					
						
							|  |  |  | 				Scan(ctx) | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		id, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-10 21:56:02 +02:00
										 |  |  | func (n *notificationDB) GetNotification( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	notificationType gtsmodel.NotificationType, | 
					
						
							|  |  |  | 	targetAccountID string, | 
					
						
							|  |  |  | 	originAccountID string, | 
					
						
							|  |  |  | 	statusID string, | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | ) (*gtsmodel.Notification, error) { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	return n.getNotification( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							|  |  |  | 		"NotificationType,TargetAccountID,OriginAccountID,StatusID", | 
					
						
							|  |  |  | 		func(notif *gtsmodel.Notification) error { | 
					
						
							|  |  |  | 			return n.db.NewSelect(). | 
					
						
							|  |  |  | 				Model(notif). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("notification_type"), notificationType). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("target_account_id"), targetAccountID). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("origin_account_id"), originAccountID). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("status_id"), statusID). | 
					
						
							|  |  |  | 				Scan(ctx) | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		notificationType, targetAccountID, originAccountID, statusID, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-04-10 21:56:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | func (n *notificationDB) getNotification(ctx context.Context, lookup string, dbQuery func(*gtsmodel.Notification) error, keyParts ...any) (*gtsmodel.Notification, error) { | 
					
						
							|  |  |  | 	// Fetch notification from cache with loader callback | 
					
						
							|  |  |  | 	notif, err := n.state.Caches.GTS.Notification.LoadOne(lookup, func() (*gtsmodel.Notification, error) { | 
					
						
							|  |  |  | 		var notif gtsmodel.Notification | 
					
						
							| 
									
										
										
										
											2023-04-10 21:56:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 		// Not cached! Perform database query | 
					
						
							|  |  |  | 		if err := dbQuery(¬if); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2023-04-10 21:56:02 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return ¬if, nil | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	}, keyParts...) | 
					
						
							| 
									
										
										
										
											2023-11-27 16:39:44 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if gtscontext.Barebones(ctx) { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 		// Only a barebones model was requested. | 
					
						
							| 
									
										
										
										
											2023-11-27 16:39:44 +01:00
										 |  |  | 		return notif, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	if err := n.state.DB.PopulateNotification(ctx, notif); err != nil { | 
					
						
							| 
									
										
										
										
											2023-11-27 16:39:44 +01:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return notif, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | func (n *notificationDB) GetNotificationsByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Notification, error) { | 
					
						
							|  |  |  | 	// Load all notif IDs via cache loader callbacks. | 
					
						
							| 
									
										
										
										
											2024-04-02 11:03:40 +01:00
										 |  |  | 	notifs, err := n.state.Caches.GTS.Notification.LoadIDs("ID", | 
					
						
							|  |  |  | 		ids, | 
					
						
							|  |  |  | 		func(uncached []string) ([]*gtsmodel.Notification, error) { | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 			// Skip query if everything was cached. | 
					
						
							|  |  |  | 			if len(uncached) == 0 { | 
					
						
							|  |  |  | 				return nil, nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 			// Preallocate expected length of uncached notifications. | 
					
						
							|  |  |  | 			notifs := make([]*gtsmodel.Notification, 0, len(uncached)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Perform database query scanning | 
					
						
							|  |  |  | 			// the remaining (uncached) IDs. | 
					
						
							|  |  |  | 			if err := n.db.NewSelect(). | 
					
						
							|  |  |  | 				Model(¬ifs). | 
					
						
							|  |  |  | 				Where("? IN (?)", bun.Ident("id"), bun.In(uncached)). | 
					
						
							|  |  |  | 				Scan(ctx); err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return notifs, nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Reorder the notifs by their | 
					
						
							|  |  |  | 	// IDs to ensure in correct order. | 
					
						
							|  |  |  | 	getID := func(n *gtsmodel.Notification) string { return n.ID } | 
					
						
							|  |  |  | 	util.OrderBy(notifs, ids, getID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if gtscontext.Barebones(ctx) { | 
					
						
							|  |  |  | 		// no need to fully populate. | 
					
						
							|  |  |  | 		return notifs, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Populate all loaded notifs, removing those we fail to | 
					
						
							|  |  |  | 	// populate (removes needing so many nil checks everywhere). | 
					
						
							|  |  |  | 	notifs = slices.DeleteFunc(notifs, func(notif *gtsmodel.Notification) bool { | 
					
						
							|  |  |  | 		if err := n.PopulateNotification(ctx, notif); err != nil { | 
					
						
							|  |  |  | 			log.Errorf(ctx, "error populating notif %s: %v", notif.ID, err) | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return notifs, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-27 16:39:44 +01:00
										 |  |  | func (n *notificationDB) PopulateNotification(ctx context.Context, notif *gtsmodel.Notification) error { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 		errs gtserror.MultiError | 
					
						
							| 
									
										
										
										
											2023-11-27 16:39:44 +01:00
										 |  |  | 		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() | 
					
						
							| 
									
										
										
										
											2023-04-10 21:56:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | func (n *notificationDB) GetAccountNotifications( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	accountID string, | 
					
						
							|  |  |  | 	maxID string, | 
					
						
							|  |  |  | 	sinceID string, | 
					
						
							|  |  |  | 	minID string, | 
					
						
							|  |  |  | 	limit int, | 
					
						
							| 
									
										
										
										
											2024-06-17 12:50:50 -07:00
										 |  |  | 	includeTypes []string, | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	excludeTypes []string, | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | ) ([]*gtsmodel.Notification, error) { | 
					
						
							| 
									
										
										
										
											2021-08-29 15:41:41 +01:00
										 |  |  | 	// Ensure reasonable | 
					
						
							|  |  |  | 	if limit < 0 { | 
					
						
							|  |  |  | 		limit = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	// Make educated guess for slice size | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		notifIDs    = make([]string, 0, limit) | 
					
						
							|  |  |  | 		frontToBack = true | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-08-29 15:41:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	q := n.db. | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 		NewSelect(). | 
					
						
							| 
									
										
										
										
											2022-10-08 13:50:48 +02:00
										 |  |  | 		TableExpr("? AS ?", bun.Ident("notifications"), bun.Ident("notification")). | 
					
						
							|  |  |  | 		Column("notification.id") | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	if maxID == "" { | 
					
						
							|  |  |  | 		maxID = id.Highest | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	// Return only notifs LOWER (ie., older) than maxID. | 
					
						
							|  |  |  | 	q = q.Where("? < ?", bun.Ident("notification.id"), maxID) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 	if sinceID != "" { | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 		// Return only notifs HIGHER (ie., newer) than sinceID. | 
					
						
							| 
									
										
										
										
											2022-10-08 13:50:48 +02:00
										 |  |  | 		q = q.Where("? > ?", bun.Ident("notification.id"), sinceID) | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	if minID != "" { | 
					
						
							|  |  |  | 		// Return only notifs HIGHER (ie., newer) than minID. | 
					
						
							|  |  |  | 		q = q.Where("? > ?", bun.Ident("notification.id"), minID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		frontToBack = false // page up | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-17 12:50:50 -07:00
										 |  |  | 	if len(includeTypes) > 0 { | 
					
						
							|  |  |  | 		// Include only requested notification types. | 
					
						
							|  |  |  | 		q = q.Where("? IN (?)", bun.Ident("notification.notification_type"), bun.In(includeTypes)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(excludeTypes) > 0 { | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 		// Filter out unwanted notif types. | 
					
						
							| 
									
										
										
										
											2024-06-17 12:50:50 -07:00
										 |  |  | 		q = q.Where("? NOT IN (?)", bun.Ident("notification.notification_type"), bun.In(excludeTypes)) | 
					
						
							| 
									
										
										
										
											2022-08-31 13:20:52 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	// Return only notifs for this account. | 
					
						
							|  |  |  | 	q = q.Where("? = ?", bun.Ident("notification.target_account_id"), accountID) | 
					
						
							| 
									
										
										
										
											2022-03-07 11:33:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	if limit > 0 { | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 		q = q.Limit(limit) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	if frontToBack { | 
					
						
							|  |  |  | 		// Page down. | 
					
						
							|  |  |  | 		q = q.Order("notification.id DESC") | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Page up. | 
					
						
							|  |  |  | 		q = q.Order("notification.id ASC") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 	if err := q.Scan(ctx, ¬ifIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2021-08-20 12:26:56 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-04 12:27:24 +02:00
										 |  |  | 	if len(notifIDs) == 0 { | 
					
						
							|  |  |  | 		return nil, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If we're paging up, we still want notifications | 
					
						
							|  |  |  | 	// to be sorted by ID desc, so reverse ids slice. | 
					
						
							|  |  |  | 	// https://zchee.github.io/golang-wiki/SliceTricks/#reversing | 
					
						
							|  |  |  | 	if !frontToBack { | 
					
						
							|  |  |  | 		for l, r := 0, len(notifIDs)-1; l < r; l, r = l+1, r-1 { | 
					
						
							|  |  |  | 			notifIDs[l], notifIDs[r] = notifIDs[r], notifIDs[l] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	// Fetch notification models by their IDs. | 
					
						
							|  |  |  | 	return n.GetNotificationsByIDs(ctx, notifIDs) | 
					
						
							| 
									
										
										
										
											2021-08-29 15:41:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-08-01 11:13:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												[performance] refactoring + add fave / follow / request / visibility caching (#1607)
* refactor visibility checking, add caching for visibility
* invalidate visibility cache items on account / status deletes
* fix requester ID passed to visibility cache nil ptr
* de-interface caches, fix home / public timeline caching + visibility
* finish adding code comments for visibility filter
* fix angry goconst linter warnings
* actually finish adding filter visibility code comments for timeline functions
* move home timeline status author check to after visibility
* remove now-unused code
* add more code comments
* add TODO code comment, update printed cache start names
* update printed cache names on stop
* start adding separate follow(request) delete db functions, add specific visibility cache tests
* add relationship type caching
* fix getting local account follows / followed-bys, other small codebase improvements
* simplify invalidation using cache hooks, add more GetAccountBy___() functions
* fix boosting to return 404 if not boostable but no error (to not leak status ID)
* remove dead code
* improved placement of cache invalidation
* update license headers
* add example follow, follow-request config entries
* add example visibility cache configuration to config file
* use specific PutFollowRequest() instead of just Put()
* add tests for all GetAccountBy()
* add GetBlockBy() tests
* update block to check primitive fields
* update and finish adding Get{Account,Block,Follow,FollowRequest}By() tests
* fix copy-pasted code
* update envparsing test
* whitespace
* fix bun struct tag
* add license header to gtscontext
* fix old license header
* improved error creation to not use fmt.Errorf() when not needed
* fix various rebase conflicts, fix account test
* remove commented-out code, fix-up mention caching
* fix mention select bun statement
* ensure mention target account populated, pass in context to customrenderer logging
* remove more uncommented code, fix typeutil test
* add statusfave database model caching
* add status fave cache configuration
* add status fave cache example config
* woops, catch missed error. nice catch linter!
* add back testrig panic on nil db
* update example configuration to match defaults, slight tweak to cache configuration defaults
* update envparsing test with new defaults
* fetch followingget to use the follow target account
* use accounnt.IsLocal() instead of empty domain check
* use constants for the cache visibility type check
* use bun.In() for notification type restriction in db query
* include replies when fetching PublicTimeline() (to account for single-author threads in Visibility{}.StatusPublicTimelineable())
* use bun query building for nested select statements to ensure working with postgres
* update public timeline future status checks to match visibility filter
* same as previous, for home timeline
* update public timeline tests to dynamically check for appropriate statuses
* migrate accounts to allow unique constraint on public_key
* provide minimal account with publicKey
---------
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
											
										 
											2023-03-28 14:03:14 +01:00
										 |  |  | func (n *notificationDB) PutNotification(ctx context.Context, notif *gtsmodel.Notification) error { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	return n.state.Caches.GTS.Notification.Store(notif, func() error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 		_, err := n.db.NewInsert().Model(notif).Exec(ctx) | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return err | 
					
						
							| 
									
										
											  
											
												[performance] refactoring + add fave / follow / request / visibility caching (#1607)
* refactor visibility checking, add caching for visibility
* invalidate visibility cache items on account / status deletes
* fix requester ID passed to visibility cache nil ptr
* de-interface caches, fix home / public timeline caching + visibility
* finish adding code comments for visibility filter
* fix angry goconst linter warnings
* actually finish adding filter visibility code comments for timeline functions
* move home timeline status author check to after visibility
* remove now-unused code
* add more code comments
* add TODO code comment, update printed cache start names
* update printed cache names on stop
* start adding separate follow(request) delete db functions, add specific visibility cache tests
* add relationship type caching
* fix getting local account follows / followed-bys, other small codebase improvements
* simplify invalidation using cache hooks, add more GetAccountBy___() functions
* fix boosting to return 404 if not boostable but no error (to not leak status ID)
* remove dead code
* improved placement of cache invalidation
* update license headers
* add example follow, follow-request config entries
* add example visibility cache configuration to config file
* use specific PutFollowRequest() instead of just Put()
* add tests for all GetAccountBy()
* add GetBlockBy() tests
* update block to check primitive fields
* update and finish adding Get{Account,Block,Follow,FollowRequest}By() tests
* fix copy-pasted code
* update envparsing test
* whitespace
* fix bun struct tag
* add license header to gtscontext
* fix old license header
* improved error creation to not use fmt.Errorf() when not needed
* fix various rebase conflicts, fix account test
* remove commented-out code, fix-up mention caching
* fix mention select bun statement
* ensure mention target account populated, pass in context to customrenderer logging
* remove more uncommented code, fix typeutil test
* add statusfave database model caching
* add status fave cache configuration
* add status fave cache example config
* woops, catch missed error. nice catch linter!
* add back testrig panic on nil db
* update example configuration to match defaults, slight tweak to cache configuration defaults
* update envparsing test with new defaults
* fetch followingget to use the follow target account
* use accounnt.IsLocal() instead of empty domain check
* use constants for the cache visibility type check
* use bun.In() for notification type restriction in db query
* include replies when fetching PublicTimeline() (to account for single-author threads in Visibility{}.StatusPublicTimelineable())
* use bun query building for nested select statements to ensure working with postgres
* update public timeline future status checks to match visibility filter
* same as previous, for home timeline
* update public timeline tests to dynamically check for appropriate statuses
* migrate accounts to allow unique constraint on public_key
* provide minimal account with publicKey
---------
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
											
										 
											2023-03-28 14:03:14 +01:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (n *notificationDB) DeleteNotificationByID(ctx context.Context, id string) error { | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 	// Delete notif from DB. | 
					
						
							|  |  |  | 	if _, err := n.db. | 
					
						
							|  |  |  | 		NewDelete(). | 
					
						
							|  |  |  | 		Table("notifications"). | 
					
						
							|  |  |  | 		Where("? = ?", bun.Ident("id"), id). | 
					
						
							|  |  |  | 		Exec(ctx); err != nil { | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2022-08-01 11:13:49 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 	// Invalidate deleted notification by ID. | 
					
						
							|  |  |  | 	n.state.Caches.GTS.Notification.Invalidate("ID", id) | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (n *notificationDB) DeleteNotifications(ctx context.Context, types []string, targetAccountID string, originAccountID string) error { | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	if targetAccountID == "" && originAccountID == "" { | 
					
						
							|  |  |  | 		return errors.New("DeleteNotifications: one of targetAccountID or originAccountID must be set") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	q := n.db. | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 		NewDelete(). | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		Table("notifications") | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												[performance] refactoring + add fave / follow / request / visibility caching (#1607)
* refactor visibility checking, add caching for visibility
* invalidate visibility cache items on account / status deletes
* fix requester ID passed to visibility cache nil ptr
* de-interface caches, fix home / public timeline caching + visibility
* finish adding code comments for visibility filter
* fix angry goconst linter warnings
* actually finish adding filter visibility code comments for timeline functions
* move home timeline status author check to after visibility
* remove now-unused code
* add more code comments
* add TODO code comment, update printed cache start names
* update printed cache names on stop
* start adding separate follow(request) delete db functions, add specific visibility cache tests
* add relationship type caching
* fix getting local account follows / followed-bys, other small codebase improvements
* simplify invalidation using cache hooks, add more GetAccountBy___() functions
* fix boosting to return 404 if not boostable but no error (to not leak status ID)
* remove dead code
* improved placement of cache invalidation
* update license headers
* add example follow, follow-request config entries
* add example visibility cache configuration to config file
* use specific PutFollowRequest() instead of just Put()
* add tests for all GetAccountBy()
* add GetBlockBy() tests
* update block to check primitive fields
* update and finish adding Get{Account,Block,Follow,FollowRequest}By() tests
* fix copy-pasted code
* update envparsing test
* whitespace
* fix bun struct tag
* add license header to gtscontext
* fix old license header
* improved error creation to not use fmt.Errorf() when not needed
* fix various rebase conflicts, fix account test
* remove commented-out code, fix-up mention caching
* fix mention select bun statement
* ensure mention target account populated, pass in context to customrenderer logging
* remove more uncommented code, fix typeutil test
* add statusfave database model caching
* add status fave cache configuration
* add status fave cache example config
* woops, catch missed error. nice catch linter!
* add back testrig panic on nil db
* update example configuration to match defaults, slight tweak to cache configuration defaults
* update envparsing test with new defaults
* fetch followingget to use the follow target account
* use accounnt.IsLocal() instead of empty domain check
* use constants for the cache visibility type check
* use bun.In() for notification type restriction in db query
* include replies when fetching PublicTimeline() (to account for single-author threads in Visibility{}.StatusPublicTimelineable())
* use bun query building for nested select statements to ensure working with postgres
* update public timeline future status checks to match visibility filter
* same as previous, for home timeline
* update public timeline tests to dynamically check for appropriate statuses
* migrate accounts to allow unique constraint on public_key
* provide minimal account with publicKey
---------
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
											
										 
											2023-03-28 14:03:14 +01:00
										 |  |  | 	if len(types) > 0 { | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		q = q.Where("? IN (?)", bun.Ident("notification_type"), bun.In(types)) | 
					
						
							| 
									
										
											  
											
												[performance] refactoring + add fave / follow / request / visibility caching (#1607)
* refactor visibility checking, add caching for visibility
* invalidate visibility cache items on account / status deletes
* fix requester ID passed to visibility cache nil ptr
* de-interface caches, fix home / public timeline caching + visibility
* finish adding code comments for visibility filter
* fix angry goconst linter warnings
* actually finish adding filter visibility code comments for timeline functions
* move home timeline status author check to after visibility
* remove now-unused code
* add more code comments
* add TODO code comment, update printed cache start names
* update printed cache names on stop
* start adding separate follow(request) delete db functions, add specific visibility cache tests
* add relationship type caching
* fix getting local account follows / followed-bys, other small codebase improvements
* simplify invalidation using cache hooks, add more GetAccountBy___() functions
* fix boosting to return 404 if not boostable but no error (to not leak status ID)
* remove dead code
* improved placement of cache invalidation
* update license headers
* add example follow, follow-request config entries
* add example visibility cache configuration to config file
* use specific PutFollowRequest() instead of just Put()
* add tests for all GetAccountBy()
* add GetBlockBy() tests
* update block to check primitive fields
* update and finish adding Get{Account,Block,Follow,FollowRequest}By() tests
* fix copy-pasted code
* update envparsing test
* whitespace
* fix bun struct tag
* add license header to gtscontext
* fix old license header
* improved error creation to not use fmt.Errorf() when not needed
* fix various rebase conflicts, fix account test
* remove commented-out code, fix-up mention caching
* fix mention select bun statement
* ensure mention target account populated, pass in context to customrenderer logging
* remove more uncommented code, fix typeutil test
* add statusfave database model caching
* add status fave cache configuration
* add status fave cache example config
* woops, catch missed error. nice catch linter!
* add back testrig panic on nil db
* update example configuration to match defaults, slight tweak to cache configuration defaults
* update envparsing test with new defaults
* fetch followingget to use the follow target account
* use accounnt.IsLocal() instead of empty domain check
* use constants for the cache visibility type check
* use bun.In() for notification type restriction in db query
* include replies when fetching PublicTimeline() (to account for single-author threads in Visibility{}.StatusPublicTimelineable())
* use bun query building for nested select statements to ensure working with postgres
* update public timeline future status checks to match visibility filter
* same as previous, for home timeline
* update public timeline tests to dynamically check for appropriate statuses
* migrate accounts to allow unique constraint on public_key
* provide minimal account with publicKey
---------
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
											
										 
											2023-03-28 14:03:14 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	if targetAccountID != "" { | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		q = q.Where("? = ?", bun.Ident("target_account_id"), targetAccountID) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if originAccountID != "" { | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		q = q.Where("? = ?", bun.Ident("origin_account_id"), originAccountID) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 	var notifIDs []string | 
					
						
							|  |  |  | 	q = q.Returning("?", bun.Ident("id")) | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 	// Delete from DB. | 
					
						
							|  |  |  | 	if _, err := q. | 
					
						
							|  |  |  | 		Exec(ctx, ¬ifIDs); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 	// Invalidate all deleted notifications by IDs. | 
					
						
							|  |  |  | 	n.state.Caches.GTS.Notification.InvalidateIDs("ID", notifIDs) | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (n *notificationDB) DeleteNotificationsForStatus(ctx context.Context, statusID string) error { | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	var notifIDs []string | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 	if _, err := n.db. | 
					
						
							|  |  |  | 		NewDelete(). | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 		Table("notifications"). | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 		Where("? = ?", bun.Ident("status_id"), statusID). | 
					
						
							|  |  |  | 		Returning("?", bun.Ident("id")). | 
					
						
							|  |  |  | 		Exec(ctx, ¬ifIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 12:14:55 +02:00
										 |  |  | 	// Invalidate all deleted notifications by IDs. | 
					
						
							|  |  |  | 	n.state.Caches.GTS.Notification.InvalidateIDs("ID", notifIDs) | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2022-08-01 11:13:49 +02:00
										 |  |  | } |