This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

semble / src / modules / cards / application / useCases / queries / GetCollectionsUseCase.ts
4.6 kB 164 lines
1import { err, ok, Result } from 'src/shared/core/Result'; 2import { UseCase } from 'src/shared/core/UseCase'; 3import { 4 ICollectionQueryRepository, 5 CollectionSortField, 6 SortOrder, 7} from '../../../domain/ICollectionQueryRepository'; 8import { IProfileService } from 'src/modules/cards/domain/services/IProfileService'; 9import { DIDOrHandle } from 'src/modules/atproto/domain/DIDOrHandle'; 10import { IIdentityResolutionService } from 'src/modules/atproto/domain/services/IIdentityResolutionService'; 11 12export interface GetCollectionsQuery { 13 curatorId: string; 14 page?: number; 15 limit?: number; 16 sortBy?: CollectionSortField; 17 sortOrder?: SortOrder; 18 searchText?: string; 19} 20 21// Enriched data for the final use case result 22export interface CollectionListItemDTO { 23 id: string; 24 uri?: string; 25 name: string; 26 description?: string; 27 updatedAt: Date; 28 createdAt: Date; 29 cardCount: number; 30 author: { 31 id: string; 32 name: string; 33 handle: string; 34 avatarUrl?: string; 35 description?: string; 36 }; 37} 38export interface GetCollectionsResult { 39 collections: CollectionListItemDTO[]; 40 pagination: { 41 currentPage: number; 42 totalPages: number; 43 totalCount: number; 44 hasMore: boolean; 45 limit: number; 46 }; 47 sorting: { 48 sortBy: CollectionSortField; 49 sortOrder: SortOrder; 50 }; 51} 52 53export class ValidationError extends Error { 54 constructor(message: string) { 55 super(message); 56 this.name = 'ValidationError'; 57 } 58} 59 60export class GetCollectionsUseCase 61 implements UseCase<GetCollectionsQuery, Result<GetCollectionsResult>> 62{ 63 constructor( 64 private collectionQueryRepo: ICollectionQueryRepository, 65 private profileService: IProfileService, 66 private identityResolver: IIdentityResolutionService, 67 ) {} 68 69 async execute( 70 query: GetCollectionsQuery, 71 ): Promise<Result<GetCollectionsResult>> { 72 // Set defaults 73 const page = query.page || 1; 74 const limit = Math.min(query.limit || 20, 100); // Cap at 100 75 const sortBy = query.sortBy || CollectionSortField.UPDATED_AT; 76 const sortOrder = query.sortOrder || SortOrder.DESC; 77 78 // Parse and validate curator identifier 79 const identifierResult = DIDOrHandle.create(query.curatorId); 80 if (identifierResult.isErr()) { 81 return err(new ValidationError('Invalid curator identifier')); 82 } 83 84 // Resolve to DID 85 const didResult = await this.identityResolver.resolveToDID( 86 identifierResult.value, 87 ); 88 if (didResult.isErr()) { 89 return err( 90 new ValidationError( 91 `Could not resolve curator identifier: ${didResult.error.message}`, 92 ), 93 ); 94 } 95 96 const resolvedDid = didResult.value.value; 97 98 try { 99 // Execute query to get raw collection data using the resolved DID 100 const result = await this.collectionQueryRepo.findByCreator(resolvedDid, { 101 page, 102 limit, 103 sortBy, 104 sortOrder, 105 searchText: query.searchText, 106 }); 107 108 // Get user profile for the curator using the resolved DID 109 const profileResult = await this.profileService.getProfile(resolvedDid); 110 111 if (profileResult.isErr()) { 112 return err( 113 new Error( 114 `Failed to fetch user profile: ${profileResult.error instanceof Error ? profileResult.error.message : 'Unknown error'}`, 115 ), 116 ); 117 } 118 const profile = profileResult.value; 119 120 // Transform raw data to enriched DTOs 121 const enrichedCollections: CollectionListItemDTO[] = result.items.map( 122 (item) => { 123 return { 124 id: item.id, 125 uri: item.uri, 126 name: item.name, 127 description: item.description, 128 updatedAt: item.updatedAt, 129 createdAt: item.createdAt, 130 cardCount: item.cardCount, 131 author: { 132 id: profile.id, 133 name: profile.name, 134 handle: profile.handle, 135 avatarUrl: profile.avatarUrl, 136 description: profile.bio, 137 }, 138 }; 139 }, 140 ); 141 142 return ok({ 143 collections: enrichedCollections, 144 pagination: { 145 currentPage: page, 146 totalPages: Math.ceil(result.totalCount / limit), 147 totalCount: result.totalCount, 148 hasMore: page * limit < result.totalCount, 149 limit, 150 }, 151 sorting: { 152 sortBy, 153 sortOrder, 154 }, 155 }); 156 } catch (error) { 157 return err( 158 new Error( 159 `Failed to retrieve collections: ${error instanceof Error ? error.message : 'Unknown error'}`, 160 ), 161 ); 162 } 163 } 164}