| 
									
										
										
										
											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/>. | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | package bundb | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	"database/sql" | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	"slices" | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/db" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/log" | 
					
						
							| 
									
										
										
										
											2024-01-31 13:31:53 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/paging" | 
					
						
							| 
									
										
										
										
											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-09-06 12:42:55 +02:00
										 |  |  | 	"github.com/uptrace/bun" | 
					
						
							| 
									
										
										
										
											2022-10-12 15:01:42 +02:00
										 |  |  | 	"github.com/uptrace/bun/dialect" | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type emojiDB struct { | 
					
						
							| 
									
										
										
										
											2024-02-07 14:43:27 +00:00
										 |  |  | 	db    *bun.DB | 
					
						
							| 
									
										
										
										
											2022-12-08 17:35:14 +00:00
										 |  |  | 	state *state.State | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) PutEmoji(ctx context.Context, emoji *gtsmodel.Emoji) error { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	return e.state.Caches.GTS.Emoji.Store(emoji, func() error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 		_, err := e.db.NewInsert().Model(emoji).Exec(ctx) | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | func (e *emojiDB) UpdateEmoji(ctx context.Context, emoji *gtsmodel.Emoji, columns ...string) error { | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 	emoji.UpdatedAt = time.Now() | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	if len(columns) > 0 { | 
					
						
							|  |  |  | 		// If we're updating by column, ensure "updated_at" is included. | 
					
						
							|  |  |  | 		columns = append(columns, "updated_at") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	// Update the emoji model in the database. | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	return e.state.Caches.GTS.Emoji.Store(emoji, func() error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 		_, err := e.db. | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 			NewUpdate(). | 
					
						
							|  |  |  | 			Model(emoji). | 
					
						
							|  |  |  | 			Where("? = ?", bun.Ident("emoji.id"), emoji.ID). | 
					
						
							|  |  |  | 			Column(columns...). | 
					
						
							|  |  |  | 			Exec(ctx) | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2022-10-14 17:30:04 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) DeleteEmojiByID(ctx context.Context, id string) error { | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		accountIDs []string | 
					
						
							|  |  |  | 		statusIDs  []string | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		// Invalidate cached emoji. | 
					
						
							| 
									
										
										
										
											2024-04-02 11:03:40 +01:00
										 |  |  | 		e.state.Caches.GTS.Emoji.Invalidate("ID", id) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 11:03:40 +01:00
										 |  |  | 		// Invalidate cached account and status IDs. | 
					
						
							|  |  |  | 		e.state.Caches.GTS.Account.InvalidateIDs("ID", accountIDs) | 
					
						
							|  |  |  | 		e.state.Caches.GTS.Status.InvalidateIDs("ID", statusIDs) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Load emoji into cache before attempting a delete, | 
					
						
							|  |  |  | 	// as we need it cached in order to trigger the invalidate | 
					
						
							|  |  |  | 	// callback. This in turn invalidates others. | 
					
						
							|  |  |  | 	_, err := e.GetEmojiByID( | 
					
						
							|  |  |  | 		gtscontext.SetBarebones(ctx), | 
					
						
							|  |  |  | 		id, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 		// NOTE: even if db.ErrNoEntries is returned, we | 
					
						
							|  |  |  | 		// still run the below transaction to ensure related | 
					
						
							|  |  |  | 		// objects are appropriately deleted. | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-07 14:43:27 +00:00
										 |  |  | 	return e.db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { | 
					
						
							| 
									
										
										
										
											2023-08-02 15:11:23 +01:00
										 |  |  | 		// Delete relational links between this emoji | 
					
						
							|  |  |  | 		// and any statuses using it, returning the | 
					
						
							|  |  |  | 		// status IDs so we can later update them. | 
					
						
							|  |  |  | 		if _, err := tx.NewDelete(). | 
					
						
							|  |  |  | 			Table("status_to_emojis"). | 
					
						
							|  |  |  | 			Where("? = ?", bun.Ident("emoji_id"), id). | 
					
						
							|  |  |  | 			Returning("status_id"). | 
					
						
							|  |  |  | 			Exec(ctx, &statusIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2022-10-14 17:30:04 +02:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-02 15:11:23 +01:00
										 |  |  | 		// Delete relational links between this emoji | 
					
						
							|  |  |  | 		// and any accounts using it, returning the | 
					
						
							|  |  |  | 		// account IDs so we can later update them. | 
					
						
							|  |  |  | 		if _, err := tx.NewDelete(). | 
					
						
							|  |  |  | 			Table("account_to_emojis"). | 
					
						
							|  |  |  | 			Where("? = ?", bun.Ident("emoji_id"), id). | 
					
						
							|  |  |  | 			Returning("account_id"). | 
					
						
							|  |  |  | 			Exec(ctx, &accountIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 		for _, statusID := range statusIDs { | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 			status := new(gtsmodel.Status) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 			// Select status emoji IDs. | 
					
						
							|  |  |  | 			if err := tx.NewSelect(). | 
					
						
							|  |  |  | 				Model(status). | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				Column("emojis"). | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 				Where("? = ?", bun.Ident("id"), statusID). | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 				Scan(ctx); err != nil && | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				err != sql.ErrNoRows { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 			// Delete all instances of this | 
					
						
							|  |  |  | 			// emoji ID from status emoji IDs. | 
					
						
							|  |  |  | 			status.EmojiIDs = slices.DeleteFunc( | 
					
						
							|  |  |  | 				status.EmojiIDs, | 
					
						
							|  |  |  | 				func(emojiID string) bool { | 
					
						
							|  |  |  | 					return emojiID == id | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-02 15:11:23 +01:00
										 |  |  | 			// Update status emoji IDs. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 			if _, err := tx.NewUpdate(). | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 				Model(status). | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 				Where("? = ?", bun.Ident("id"), statusID). | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 				Column("emojis"). | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				Exec(ctx); err != nil && | 
					
						
							|  |  |  | 				err != sql.ErrNoRows { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 		for _, accountID := range accountIDs { | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 			account := new(gtsmodel.Account) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 			// Select account emoji IDs. | 
					
						
							|  |  |  | 			if err := tx.NewSelect(). | 
					
						
							|  |  |  | 				Model(account). | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				Column("emojis"). | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 				Where("? = ?", bun.Ident("id"), accountID). | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 				Scan(ctx); err != nil && | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				err != sql.ErrNoRows { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 			// Delete all instances of this | 
					
						
							|  |  |  | 			// emoji ID from account emoji IDs. | 
					
						
							|  |  |  | 			account.EmojiIDs = slices.DeleteFunc( | 
					
						
							|  |  |  | 				account.EmojiIDs, | 
					
						
							|  |  |  | 				func(emojiID string) bool { | 
					
						
							|  |  |  | 					return emojiID == id | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-02 15:11:23 +01:00
										 |  |  | 			// Update account emoji IDs. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 			if _, err := tx.NewUpdate(). | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 				Model(account). | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 				Where("? = ?", bun.Ident("id"), accountID). | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 				Column("emojis"). | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				Exec(ctx); err != nil && | 
					
						
							|  |  |  | 				err != sql.ErrNoRows { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-29 15:57:22 +01:00
										 |  |  | 		// Finally, delete emoji from database. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 		if _, err := tx.NewDelete(). | 
					
						
							|  |  |  | 			Table("emojis"). | 
					
						
							| 
									
										
										
										
											2023-08-02 15:11:23 +01:00
										 |  |  | 			Where("? = ?", bun.Ident("id"), id). | 
					
						
							| 
									
										
										
										
											2022-10-14 17:30:04 +02:00
										 |  |  | 			Exec(ctx); err != nil { | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2022-10-14 17:30:04 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2023-05-12 10:15:54 +01:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | func (e *emojiDB) GetEmojisBy(ctx context.Context, domain string, includeDisabled bool, includeEnabled bool, shortcode string, maxShortcodeDomain string, minShortcodeDomain string, limit int) ([]*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2022-10-12 15:01:42 +02:00
										 |  |  | 	emojiIDs := []string{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	subQuery := e.db. | 
					
						
							| 
									
										
										
										
											2022-10-12 15:01:42 +02:00
										 |  |  | 		NewSelect(). | 
					
						
							|  |  |  | 		ColumnExpr("? AS ?", bun.Ident("emoji.id"), bun.Ident("emoji_ids")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// To ensure consistent ordering and make paging possible, we sort not by shortcode | 
					
						
							|  |  |  | 	// but by [shortcode]@[domain]. Because sqlite and postgres have different syntax | 
					
						
							|  |  |  | 	// for concatenation, that means we need to switch here. Depending on which driver | 
					
						
							|  |  |  | 	// is in use, query will look something like this (sqlite): | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	//	SELECT | 
					
						
							|  |  |  | 	//		"emoji"."id" AS "emoji_ids", | 
					
						
							|  |  |  | 	//		lower("emoji"."shortcode" || '@' || COALESCE("emoji"."domain", '')) AS "shortcode_domain" | 
					
						
							|  |  |  | 	//	FROM | 
					
						
							|  |  |  | 	//		"emojis" AS "emoji" | 
					
						
							|  |  |  | 	//	ORDER BY | 
					
						
							|  |  |  | 	//		"shortcode_domain" ASC | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// Or like this (postgres): | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	//	SELECT | 
					
						
							|  |  |  | 	//		"emoji"."id" AS "emoji_ids", | 
					
						
							|  |  |  | 	//		LOWER(CONCAT("emoji"."shortcode", '@', COALESCE("emoji"."domain", ''))) AS "shortcode_domain" | 
					
						
							|  |  |  | 	//	FROM | 
					
						
							|  |  |  | 	//		"emojis" AS "emoji" | 
					
						
							|  |  |  | 	//	ORDER BY | 
					
						
							|  |  |  | 	//		"shortcode_domain" ASC | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	switch e.db.Dialect().Name() { | 
					
						
							| 
									
										
										
										
											2022-10-12 15:01:42 +02:00
										 |  |  | 	case dialect.SQLite: | 
					
						
							|  |  |  | 		subQuery = subQuery.ColumnExpr("LOWER(? || ? || COALESCE(?, ?)) AS ?", bun.Ident("emoji.shortcode"), "@", bun.Ident("emoji.domain"), "", bun.Ident("shortcode_domain")) | 
					
						
							|  |  |  | 	case dialect.PG: | 
					
						
							|  |  |  | 		subQuery = subQuery.ColumnExpr("LOWER(CONCAT(?, ?, COALESCE(?, ?))) AS ?", bun.Ident("emoji.shortcode"), "@", bun.Ident("emoji.domain"), "", bun.Ident("shortcode_domain")) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		panic("db conn was neither pg not sqlite") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	subQuery = subQuery.TableExpr("? AS ?", bun.Ident("emojis"), bun.Ident("emoji")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if domain == "" { | 
					
						
							|  |  |  | 		subQuery = subQuery.Where("? IS NULL", bun.Ident("emoji.domain")) | 
					
						
							|  |  |  | 	} else if domain != db.EmojiAllDomains { | 
					
						
							|  |  |  | 		subQuery = subQuery.Where("? = ?", bun.Ident("emoji.domain"), domain) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case includeDisabled && !includeEnabled: | 
					
						
							|  |  |  | 		// show only disabled emojis | 
					
						
							|  |  |  | 		subQuery = subQuery.Where("? = ?", bun.Ident("emoji.disabled"), true) | 
					
						
							|  |  |  | 	case includeEnabled && !includeDisabled: | 
					
						
							|  |  |  | 		// show only enabled emojis | 
					
						
							|  |  |  | 		subQuery = subQuery.Where("? = ?", bun.Ident("emoji.disabled"), false) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		// show emojis regardless of emoji.disabled value | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if shortcode != "" { | 
					
						
							|  |  |  | 		subQuery = subQuery.Where("LOWER(?) = LOWER(?)", bun.Ident("emoji.shortcode"), shortcode) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// assume we want to sort ASC (a-z) unless informed otherwise | 
					
						
							|  |  |  | 	order := "ASC" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if maxShortcodeDomain != "" { | 
					
						
							|  |  |  | 		subQuery = subQuery.Where("? > LOWER(?)", bun.Ident("shortcode_domain"), maxShortcodeDomain) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if minShortcodeDomain != "" { | 
					
						
							|  |  |  | 		subQuery = subQuery.Where("? < LOWER(?)", bun.Ident("shortcode_domain"), minShortcodeDomain) | 
					
						
							|  |  |  | 		// if we have a minShortcodeDomain we're paging upwards/backwards | 
					
						
							|  |  |  | 		order = "DESC" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	subQuery = subQuery.Order("shortcode_domain " + order) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if limit > 0 { | 
					
						
							|  |  |  | 		subQuery = subQuery.Limit(limit) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Wrap the subQuery in a query, since we don't need to select the shortcode_domain column. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// The final query will come out looking something like... | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	//	SELECT | 
					
						
							|  |  |  | 	//		"subquery"."emoji_ids" | 
					
						
							|  |  |  | 	//	FROM ( | 
					
						
							|  |  |  | 	//		SELECT | 
					
						
							|  |  |  | 	//			"emoji"."id" AS "emoji_ids", | 
					
						
							|  |  |  | 	//			LOWER("emoji"."shortcode" || '@' || COALESCE("emoji"."domain", '')) AS "shortcode_domain" | 
					
						
							|  |  |  | 	//		FROM | 
					
						
							|  |  |  | 	//			"emojis" AS "emoji" | 
					
						
							|  |  |  | 	//		ORDER BY | 
					
						
							|  |  |  | 	//			"shortcode_domain" ASC | 
					
						
							|  |  |  | 	//	) AS "subquery" | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	if err := e.db. | 
					
						
							| 
									
										
										
										
											2022-10-12 15:01:42 +02:00
										 |  |  | 		NewSelect(). | 
					
						
							|  |  |  | 		Column("subquery.emoji_ids"). | 
					
						
							|  |  |  | 		TableExpr("(?) AS ?", subQuery, bun.Ident("subquery")). | 
					
						
							|  |  |  | 		Scan(ctx, &emojiIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2022-10-12 15:01:42 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if order == "DESC" { | 
					
						
							|  |  |  | 		// Reverse the slice order so the caller still | 
					
						
							|  |  |  | 		// gets emojis in expected a-z alphabetical order. | 
					
						
							|  |  |  | 		// | 
					
						
							|  |  |  | 		// See https://github.com/golang/go/wiki/SliceTricks#reversing | 
					
						
							|  |  |  | 		for i := len(emojiIDs)/2 - 1; i >= 0; i-- { | 
					
						
							|  |  |  | 			opp := len(emojiIDs) - 1 - i | 
					
						
							|  |  |  | 			emojiIDs[i], emojiIDs[opp] = emojiIDs[opp], emojiIDs[i] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 17:35:14 +00:00
										 |  |  | 	return e.GetEmojisByIDs(ctx, emojiIDs) | 
					
						
							| 
									
										
										
										
											2022-10-12 15:01:42 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-31 13:31:53 +00:00
										 |  |  | func (e *emojiDB) GetEmojis(ctx context.Context, page *paging.Page) ([]*gtsmodel.Emoji, error) { | 
					
						
							|  |  |  | 	maxID := page.GetMax() | 
					
						
							|  |  |  | 	limit := page.GetLimit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	emojiIDs := make([]string, 0, limit) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	q := e.db.NewSelect(). | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 		Table("emojis"). | 
					
						
							|  |  |  | 		Column("id"). | 
					
						
							|  |  |  | 		Order("id DESC") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if maxID != "" { | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 		q = q.Where("id < ?", maxID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if limit != 0 { | 
					
						
							|  |  |  | 		q = q.Limit(limit) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 	if err := q.Scan(ctx, &emojiIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return e.GetEmojisByIDs(ctx, emojiIDs) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-31 13:31:53 +00:00
										 |  |  | func (e *emojiDB) GetRemoteEmojis(ctx context.Context, page *paging.Page) ([]*gtsmodel.Emoji, error) { | 
					
						
							|  |  |  | 	maxID := page.GetMax() | 
					
						
							|  |  |  | 	limit := page.GetLimit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	emojiIDs := make([]string, 0, limit) | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	q := e.db.NewSelect(). | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 		Table("emojis"). | 
					
						
							|  |  |  | 		Column("id"). | 
					
						
							|  |  |  | 		Where("domain IS NOT NULL"). | 
					
						
							|  |  |  | 		Order("id DESC") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if maxID != "" { | 
					
						
							|  |  |  | 		q = q.Where("id < ?", maxID) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if limit != 0 { | 
					
						
							|  |  |  | 		q = q.Limit(limit) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := q.Scan(ctx, &emojiIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return e.GetEmojisByIDs(ctx, emojiIDs) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e *emojiDB) GetCachedEmojisOlderThan(ctx context.Context, olderThan time.Time, limit int) ([]*gtsmodel.Emoji, error) { | 
					
						
							|  |  |  | 	var emojiIDs []string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	q := e.db.NewSelect(). | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 		Table("emojis"). | 
					
						
							|  |  |  | 		Column("id"). | 
					
						
							|  |  |  | 		Where("cached = true"). | 
					
						
							|  |  |  | 		Where("domain IS NOT NULL"). | 
					
						
							|  |  |  | 		Where("created_at < ?", olderThan). | 
					
						
							|  |  |  | 		Order("created_at DESC") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	if limit != 0 { | 
					
						
							|  |  |  | 		q = q.Limit(limit) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := q.Scan(ctx, &emojiIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return e.GetEmojisByIDs(ctx, emojiIDs) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetUseableEmojis(ctx context.Context) ([]*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	emojiIDs := []string{} | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	q := e.db. | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 		NewSelect(). | 
					
						
							| 
									
										
										
										
											2022-10-08 13:50:48 +02:00
										 |  |  | 		TableExpr("? AS ?", bun.Ident("emojis"), bun.Ident("emoji")). | 
					
						
							|  |  |  | 		Column("emoji.id"). | 
					
						
							|  |  |  | 		Where("? = ?", bun.Ident("emoji.visible_in_picker"), true). | 
					
						
							|  |  |  | 		Where("? = ?", bun.Ident("emoji.disabled"), false). | 
					
						
							|  |  |  | 		Where("? IS NULL", bun.Ident("emoji.domain")). | 
					
						
							|  |  |  | 		Order("emoji.shortcode ASC") | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	if err := q.Scan(ctx, &emojiIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 17:35:14 +00:00
										 |  |  | 	return e.GetEmojisByIDs(ctx, emojiIDs) | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetEmojiByID(ctx context.Context, id string) (*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	return e.getEmoji( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		"ID", | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 		func(emoji *gtsmodel.Emoji) error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 			return e.db. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				NewSelect(). | 
					
						
							|  |  |  | 				Model(emoji). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("emoji.id"), id).Scan(ctx) | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		id, | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetEmojiByURI(ctx context.Context, uri string) (*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	return e.getEmoji( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		"URI", | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 		func(emoji *gtsmodel.Emoji) error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 			return e.db. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				NewSelect(). | 
					
						
							|  |  |  | 				Model(emoji). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("emoji.uri"), uri).Scan(ctx) | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		uri, | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetEmojiByShortcodeDomain(ctx context.Context, shortcode string, domain string) (*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	return e.getEmoji( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 		"Shortcode,Domain", | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 		func(emoji *gtsmodel.Emoji) error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 			q := e.db. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				NewSelect(). | 
					
						
							|  |  |  | 				Model(emoji) | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if domain != "" { | 
					
						
							| 
									
										
										
										
											2022-10-08 13:50:48 +02:00
										 |  |  | 				q = q.Where("? = ?", bun.Ident("emoji.shortcode"), shortcode) | 
					
						
							|  |  |  | 				q = q.Where("? = ?", bun.Ident("emoji.domain"), domain) | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2022-10-08 13:50:48 +02:00
										 |  |  | 				q = q.Where("? = ?", bun.Ident("emoji.shortcode"), strings.ToLower(shortcode)) | 
					
						
							|  |  |  | 				q = q.Where("? IS NULL", bun.Ident("emoji.domain")) | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return q.Scan(ctx) | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		shortcode, | 
					
						
							|  |  |  | 		domain, | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetEmojiByStaticURL(ctx context.Context, imageStaticURL string) (*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 	return e.getEmoji( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		"ImageStaticURL", | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 		func(emoji *gtsmodel.Emoji) error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 			return e.db. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				NewSelect(). | 
					
						
							|  |  |  | 				Model(emoji). | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 				Where("? = ?", bun.Ident("emoji.image_static_url"), imageStaticURL). | 
					
						
							|  |  |  | 				Scan(ctx) | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		imageStaticURL, | 
					
						
							| 
									
										
										
										
											2022-10-13 15:16:24 +02:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) PutEmojiCategory(ctx context.Context, emojiCategory *gtsmodel.EmojiCategory) error { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	return e.state.Caches.GTS.EmojiCategory.Store(emojiCategory, func() error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 		_, err := e.db.NewInsert().Model(emojiCategory).Exec(ctx) | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetEmojiCategories(ctx context.Context) ([]*gtsmodel.EmojiCategory, error) { | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 	emojiCategoryIDs := []string{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 	q := e.db. | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 		NewSelect(). | 
					
						
							|  |  |  | 		TableExpr("? AS ?", bun.Ident("emoji_categories"), bun.Ident("emoji_category")). | 
					
						
							|  |  |  | 		Column("emoji_category.id"). | 
					
						
							|  |  |  | 		Order("emoji_category.name ASC") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := q.Scan(ctx, &emojiCategoryIDs); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 17:35:14 +00:00
										 |  |  | 	return e.GetEmojiCategoriesByIDs(ctx, emojiCategoryIDs) | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetEmojiCategory(ctx context.Context, id string) (*gtsmodel.EmojiCategory, error) { | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 	return e.getEmojiCategory( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		"ID", | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 		func(emojiCategory *gtsmodel.EmojiCategory) error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 			return e.db. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				NewSelect(). | 
					
						
							|  |  |  | 				Model(emojiCategory). | 
					
						
							|  |  |  | 				Where("? = ?", bun.Ident("emoji_category.id"), id).Scan(ctx) | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		id, | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) GetEmojiCategoryByName(ctx context.Context, name string) (*gtsmodel.EmojiCategory, error) { | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 	return e.getEmojiCategory( | 
					
						
							|  |  |  | 		ctx, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		"Name", | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 		func(emojiCategory *gtsmodel.EmojiCategory) error { | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | 			return e.db. | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 				NewSelect(). | 
					
						
							|  |  |  | 				Model(emojiCategory). | 
					
						
							|  |  |  | 				Where("LOWER(?) = ?", bun.Ident("emoji_category.name"), strings.ToLower(name)).Scan(ctx) | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		name, | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) getEmoji(ctx context.Context, lookup string, dbQuery func(*gtsmodel.Emoji) error, keyParts ...any) (*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	// Fetch emoji from database cache with loader callback | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	emoji, err := e.state.Caches.GTS.Emoji.LoadOne(lookup, func() (*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		var emoji gtsmodel.Emoji | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Not cached! Perform database query | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		if err := dbQuery(&emoji); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		return &emoji, nil | 
					
						
							|  |  |  | 	}, keyParts...) | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if gtscontext.Barebones(ctx) { | 
					
						
							|  |  |  | 		// no need to fully populate. | 
					
						
							|  |  |  | 		return emoji, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if emoji.CategoryID != "" { | 
					
						
							|  |  |  | 		emoji.Category, err = e.GetEmojiCategory(ctx, emoji.CategoryID) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			log.Errorf(ctx, "error getting emoji category %s: %v", emoji.CategoryID, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return emoji, nil | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-27 16:39:44 +01:00
										 |  |  | 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() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | func (e *emojiDB) GetEmojisByIDs(ctx context.Context, ids []string) ([]*gtsmodel.Emoji, error) { | 
					
						
							|  |  |  | 	if len(ids) == 0 { | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 		return nil, db.ErrNoEntries | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	// Load all emoji IDs via cache loader callbacks. | 
					
						
							| 
									
										
										
										
											2024-04-02 11:03:40 +01:00
										 |  |  | 	emojis, err := e.state.Caches.GTS.Emoji.LoadIDs("ID", | 
					
						
							|  |  |  | 		ids, | 
					
						
							|  |  |  | 		func(uncached []string) ([]*gtsmodel.Emoji, error) { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 			// Preallocate expected length of uncached emojis. | 
					
						
							|  |  |  | 			emojis := make([]*gtsmodel.Emoji, 0, len(uncached)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Perform database query scanning | 
					
						
							|  |  |  | 			// the remaining (uncached) IDs. | 
					
						
							|  |  |  | 			if err := e.db.NewSelect(). | 
					
						
							|  |  |  | 				Model(&emojis). | 
					
						
							|  |  |  | 				Where("? IN (?)", bun.Ident("id"), bun.In(uncached)). | 
					
						
							|  |  |  | 				Scan(ctx); err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return emojis, nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Reorder the emojis by their | 
					
						
							|  |  |  | 	// IDs to ensure in correct order. | 
					
						
							|  |  |  | 	getID := func(e *gtsmodel.Emoji) string { return e.ID } | 
					
						
							|  |  |  | 	util.OrderBy(emojis, ids, getID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if gtscontext.Barebones(ctx) { | 
					
						
							|  |  |  | 		// no need to fully populate. | 
					
						
							|  |  |  | 		return emojis, nil | 
					
						
							| 
									
										
										
										
											2022-09-06 12:42:55 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	// Populate all loaded emojis, removing those we fail to | 
					
						
							|  |  |  | 	// populate (removes needing so many nil checks everywhere). | 
					
						
							|  |  |  | 	emojis = slices.DeleteFunc(emojis, func(emoji *gtsmodel.Emoji) bool { | 
					
						
							|  |  |  | 		if err := e.PopulateEmoji(ctx, emoji); err != nil { | 
					
						
							|  |  |  | 			log.Errorf(ctx, "error populating emoji %s: %v", emoji.ID, err) | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-20 04:34:36 -04:00
										 |  |  | 	return emojis, nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 09:34:05 +01:00
										 |  |  | func (e *emojiDB) getEmojiCategory(ctx context.Context, lookup string, dbQuery func(*gtsmodel.EmojiCategory) error, keyParts ...any) (*gtsmodel.EmojiCategory, error) { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	return e.state.Caches.GTS.EmojiCategory.LoadOne(lookup, func() (*gtsmodel.EmojiCategory, error) { | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		var category gtsmodel.EmojiCategory | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Not cached! Perform database query | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		if err := dbQuery(&category); err != nil { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:26:21 +01:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 18:45:15 +00:00
										 |  |  | 		return &category, nil | 
					
						
							|  |  |  | 	}, keyParts...) | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | func (e *emojiDB) GetEmojiCategoriesByIDs(ctx context.Context, ids []string) ([]*gtsmodel.EmojiCategory, error) { | 
					
						
							|  |  |  | 	if len(ids) == 0 { | 
					
						
							| 
									
										
										
										
											2022-11-14 23:47:27 +01:00
										 |  |  | 		return nil, db.ErrNoEntries | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 	// Load all category IDs via cache loader callbacks. | 
					
						
							| 
									
										
										
										
											2024-04-02 11:03:40 +01:00
										 |  |  | 	categories, err := e.state.Caches.GTS.EmojiCategory.LoadIDs("ID", | 
					
						
							|  |  |  | 		ids, | 
					
						
							|  |  |  | 		func(uncached []string) ([]*gtsmodel.EmojiCategory, error) { | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 			// Preallocate expected length of uncached categories. | 
					
						
							|  |  |  | 			categories := make([]*gtsmodel.EmojiCategory, 0, len(uncached)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Perform database query scanning | 
					
						
							|  |  |  | 			// the remaining (uncached) IDs. | 
					
						
							|  |  |  | 			if err := e.db.NewSelect(). | 
					
						
							|  |  |  | 				Model(&categories). | 
					
						
							|  |  |  | 				Where("? IN (?)", bun.Ident("id"), bun.In(uncached)). | 
					
						
							|  |  |  | 				Scan(ctx); err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 			return categories, nil | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-01-19 12:57:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Reorder the categories by their | 
					
						
							|  |  |  | 	// IDs to ensure in correct order. | 
					
						
							|  |  |  | 	getID := func(c *gtsmodel.EmojiCategory) string { return c.ID } | 
					
						
							|  |  |  | 	util.OrderBy(categories, ids, getID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return categories, nil | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | } |