diff --git a/packages/api/src/entity/library_item.ts b/packages/api/src/entity/library_item.ts index 960c05635..416c65b68 100644 --- a/packages/api/src/entity/library_item.ts +++ b/packages/api/src/entity/library_item.ts @@ -198,4 +198,7 @@ export class LibraryItem { @Column('text', { nullable: true }) note?: string | null + + @Column('text', { nullable: true }) + recommenderNames?: string[] | null } diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 57f702a59..f669a5909 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -9,13 +9,16 @@ import { Highlight, Label, PageType, + Recommendation, SearchItem, } from '../generated/graphql' import { findHighlightsByLibraryItemId } from '../services/highlights' import { findLabelsByLibraryItemId } from '../services/labels' +import { findRecommendationsByLibraryItemId } from '../services/recommendation' import { findUploadFileById } from '../services/upload_file' import { highlightDataToHighlight, + recommandationDataToRecommendation, validatedDate, wordsCount, } from '../utils/helpers' @@ -502,6 +505,15 @@ export const functionResolvers = { return findLabelsByLibraryItemId(item.id, ctx.uid) }, + async recommendations(item: { + id: string + recommendations?: Recommendation[] + }) { + if (item.recommendations) return item.recommendations + + const recommendations = await findRecommendationsByLibraryItemId(item.id) + return recommendations.map(recommandationDataToRecommendation) + }, }, Subscription: { newsletterEmail(subscription: Subscription) { diff --git a/packages/api/src/services/library_item.ts b/packages/api/src/services/library_item.ts index 68868c8fd..1dcdb146d 100644 --- a/packages/api/src/services/library_item.ts +++ b/packages/api/src/services/library_item.ts @@ -6,7 +6,7 @@ import { Label } from '../entity/label' import { LibraryItem, LibraryItemState } from '../entity/library_item' import { BulkActionType } from '../generated/graphql' import { createPubSubClient, EntityType } from '../pubsub' -import { authTrx, getColumns } from '../repository' +import { authTrx } from '../repository' import { libraryItemRepository } from '../repository/library_item' import { wordsCount } from '../utils/helpers' import { @@ -245,12 +245,13 @@ const buildWhereClause = ( } if (args.recommendedBy) { - queryBuilder.andWhere('recommendations IS NOT NULL') - - // select all if * is provided - if (args.recommendedBy !== '*') { + if (args.recommendedBy === '*') { + // select all if * is provided + queryBuilder.andWhere(`library_item.recommender_names <> '{}'`) + } else { + // select only if the user is recommended by the provided user queryBuilder.andWhere( - '(lower(recommender.name) = :recommendedBy OR lower(group.name) = :recommendedBy)', + 'lower(library_item.recommender_names::text)::text[] && ARRAY[:recommendedBy]::text[]', { recommendedBy: args.recommendedBy.toLowerCase(), } @@ -275,10 +276,6 @@ export const searchLibraryItems = async ( async (tx) => { const queryBuilder = tx .createQueryBuilder(LibraryItem, 'library_item') - .leftJoinAndSelect('library_item.recommendations', 'recommendations') - .leftJoinAndSelect('recommendations.recommender', 'recommender') - .leftJoinAndSelect('recommendations.group', 'group') - .leftJoinAndSelect('recommender.profile', 'recommender_profile') .where('library_item.user_id = :userId', { userId }) // build the where clause diff --git a/packages/api/src/services/recommendation.ts b/packages/api/src/services/recommendation.ts index 933123bfe..cd5558b97 100644 --- a/packages/api/src/services/recommendation.ts +++ b/packages/api/src/services/recommendation.ts @@ -94,3 +94,15 @@ export const createRecommendation = async ( ) => { return getRepository(Recommendation).save(recommendation) } + +export const findRecommendationsByLibraryItemId = async ( + libraryItemId: string +) => { + return getRepository(Recommendation).find({ + where: { libraryItem: { id: libraryItemId } }, + relations: { + group: true, + recommender: true, + } + }) +} diff --git a/packages/api/src/utils/helpers.ts b/packages/api/src/utils/helpers.ts index 8bfc97478..e576af4e1 100644 --- a/packages/api/src/utils/helpers.ts +++ b/packages/api/src/utils/helpers.ts @@ -208,7 +208,7 @@ export const highlightDataToHighlight = ( user: userDataToUser(highlight.user), }) -const recommandationDataToRecommendation = ( +export const recommandationDataToRecommendation = ( recommendation: RecommendationData ): Recommendation => ({ ...recommendation, diff --git a/packages/db/migrations/0128.undo.create_index_for_foreign_key.sql b/packages/db/migrations/0128.undo.create_index_for_foreign_key.sql index 87612778e..51b7cfb54 100755 --- a/packages/db/migrations/0128.undo.create_index_for_foreign_key.sql +++ b/packages/db/migrations/0128.undo.create_index_for_foreign_key.sql @@ -7,7 +7,7 @@ BEGIN; DROP INDEX IF EXISTS omnivore.library_item_updated_at_idx; DROP INDEX IF EXISTS omnivore.library_item_saved_at_idx; -DROP INDEX IF NOT EXISTS omnivore.user_profile_user_id_idx; +DROP INDEX IF EXISTS omnivore.user_profile_user_id_idx; DROP INDEX IF EXISTS omnivore.highlight_library_item_id_idx; diff --git a/packages/db/migrations/0129.do.add_recommender_names_to_library_item.sql b/packages/db/migrations/0129.do.add_recommender_names_to_library_item.sql new file mode 100755 index 000000000..68f5b20d2 --- /dev/null +++ b/packages/db/migrations/0129.do.add_recommender_names_to_library_item.sql @@ -0,0 +1,37 @@ +-- Type: DO +-- Name: add_recommender_names_to_library_item +-- Description: Add recommender names field to library item table + +BEGIN; + +ALTER TABLE omnivore.library_item ADD COLUMN recommender_names text[] DEFAULT '{}'::text[]; + +CREATE OR REPLACE FUNCTION update_library_item_recommenders() +RETURNS trigger AS $$ +BEGIN + -- update library_item recommender names from user and group table name column + UPDATE omnivore.library_item + SET recommender_names = ( + SELECT array_agg(DISTINCT name) + FROM ( + SELECT name + FROM omnivore.user + WHERE id = NEW.user_id + UNION + SELECT name + FROM omnivore.group + WHERE id = NEW.group_id + ) AS recommender_names + ) + WHERE id = NEW.library_item_id; + + return NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER library_item_recommenders_update +AFTER INSERT ON omnivore.recommendation +FOR EACH ROW +EXECUTE FUNCTION update_library_item_recommenders(); + +COMMIT; diff --git a/packages/db/migrations/0129.undo.add_recommender_names_to_library_item.sql b/packages/db/migrations/0129.undo.add_recommender_names_to_library_item.sql new file mode 100755 index 000000000..6d56db7dc --- /dev/null +++ b/packages/db/migrations/0129.undo.add_recommender_names_to_library_item.sql @@ -0,0 +1,12 @@ +-- Type: UNDO +-- Name: add_recommender_names_to_library_item +-- Description: Add recommender names field to library item table + +BEGIN; + +DROP TRIGGER IF EXISTS library_item_recommenders_update ON omnivore.recommendation; +DROP FUNCTION IF EXISTS update_library_item_recommenders(); + +ALTER TABLE omnivore.library_item DROP COLUMN recommender_names; + +COMMIT;