diff --git a/frontend/src/network/network.ts b/frontend/src/network/network.ts index 6696052..1502948 100644 --- a/frontend/src/network/network.ts +++ b/frontend/src/network/network.ts @@ -730,7 +730,10 @@ class Network { ); } - async listUserCollections(username: string, page: number = 1): Promise> { + async listUserCollections( + username: string, + page: number = 1, + ): Promise> { return this._callApi(() => axios.get(`${this.apiBaseUrl}/collection/list`, { params: { username, page }, @@ -776,10 +779,11 @@ class Network { async searchUserCollections( username: string, keyword: string, + excludedRID?: number, ): Promise> { return this._callApi(() => axios.get(`${this.apiBaseUrl}/collection/search`, { - params: { username, keyword }, + params: { username, keyword, excludedRID }, }), ); } diff --git a/server/api/collection.go b/server/api/collection.go index 533e42b..0746d63 100644 --- a/server/api/collection.go +++ b/server/api/collection.go @@ -202,7 +202,14 @@ func handleSearchUserCollections(c fiber.Ctx) error { if username == "" { return model.NewRequestError("username is required") } - cols, err := service.SearchUserCollections(username, keyword) + excludedRIDStr := c.Query("excludedRID", "") + var excludedRID uint = 0 + if excludedRIDStr != "" { + if rid, err := strconv.Atoi(excludedRIDStr); err == nil && rid > 0 { + excludedRID = uint(rid) + } + } + cols, err := service.SearchUserCollections(username, keyword, excludedRID) if err != nil { return err } diff --git a/server/dao/collection.go b/server/dao/collection.go index 6c7d4d7..a4cc48e 100644 --- a/server/dao/collection.go +++ b/server/dao/collection.go @@ -176,14 +176,23 @@ func ListCollectionResources(collectionID uint, page int, pageSize int) ([]*mode } // SearchUserCollections searches for collections by user ID and keyword limited to 10 results. -func SearchUserCollections(uid uint, keyword string) ([]*model.Collection, error) { +// excludedRID: if >0, only return collections not containing this resource. +func SearchUserCollections(uid uint, keyword string, excludedRID uint) ([]*model.Collection, error) { var collections []*model.Collection - if err := db. - Model(&model.Collection{}). + query := db.Model(&model.Collection{}). + Where("user_id = ? AND title LIKE ?", uid, "%"+keyword+"%") + + if excludedRID > 0 { + // Use LEFT JOIN with IS NULL for better performance + query = query. + Joins("LEFT JOIN collection_resources cr ON collections.id = cr.collection_id AND cr.resource_id = ?", excludedRID). + Where("cr.collection_id IS NULL") + } + + if err := query. Preload("Images"). Preload("Resources"). - Where("user_id = ? AND title LIKE ?", uid, "%"+keyword+"%"). Limit(10). Find(&collections).Error; err != nil { return nil, err diff --git a/server/service/collection.go b/server/service/collection.go index e8b7edf..9cf4f0f 100644 --- a/server/service/collection.go +++ b/server/service/collection.go @@ -134,7 +134,8 @@ func ListCollectionResources(collectionID uint, page int) ([]*model.ResourceView } // Search user collections by keyword, limited to 10 results. -func SearchUserCollections(username string, keyword string) ([]*model.CollectionView, error) { +// excludedRID: if >0, only return collections not containing this resource. +func SearchUserCollections(username string, keyword string, excludedRID uint) ([]*model.CollectionView, error) { if username == "" || keyword == "" { return nil, errors.New("invalid parameters") } @@ -143,7 +144,7 @@ func SearchUserCollections(username string, keyword string) ([]*model.Collection return nil, err } uid := user.ID - collections, err := dao.SearchUserCollections(uid, keyword) + collections, err := dao.SearchUserCollections(uid, keyword, excludedRID) if err != nil { return nil, err }