A social knowledge tool for researchers built on ATProto
at development 4.1 kB view raw
1import { Result, ok, err } from '../../../../shared/core/Result'; 2import { ICollectionRepository } from '../../domain/ICollectionRepository'; 3import { Collection } from '../../domain/Collection'; 4import { CollectionId } from '../../domain/value-objects/CollectionId'; 5import { CardId } from '../../domain/value-objects/CardId'; 6import { CuratorId } from '../../domain/value-objects/CuratorId'; 7 8export class InMemoryCollectionRepository implements ICollectionRepository { 9 private collections: Map<string, Collection> = new Map(); 10 11 private clone(collection: Collection): Collection { 12 // Simple clone - in a real implementation you'd want proper deep cloning 13 const collectionResult = Collection.create( 14 { 15 authorId: collection.authorId, 16 name: collection.name.value, 17 description: collection.description?.value, 18 accessType: collection.accessType, 19 collaboratorIds: collection.collaboratorIds, 20 cardLinks: collection.cardLinks, 21 cardCount: collection.cardCount, 22 publishedRecordId: collection.publishedRecordId, 23 createdAt: collection.createdAt, 24 updatedAt: collection.updatedAt, 25 }, 26 collection.id, 27 ); 28 29 if (collectionResult.isErr()) { 30 throw new Error( 31 `Failed to clone collection: ${collectionResult.error.message}`, 32 ); 33 } 34 35 return collectionResult.value; 36 } 37 38 async findById(id: CollectionId): Promise<Result<Collection | null>> { 39 try { 40 const collection = this.collections.get(id.getStringValue()); 41 return ok(collection ? this.clone(collection) : null); 42 } catch (error) { 43 return err(error as Error); 44 } 45 } 46 47 async findByCuratorId(curatorId: CuratorId): Promise<Result<Collection[]>> { 48 try { 49 const collections = Array.from(this.collections.values()).filter( 50 (collection) => 51 collection.authorId.value === curatorId.value || 52 collection.collaboratorIds.some((id) => id.value === curatorId.value), 53 ); 54 return ok(collections.map((collection) => this.clone(collection))); 55 } catch (error) { 56 return err(error as Error); 57 } 58 } 59 60 async findByCardId(cardId: CardId): Promise<Result<Collection[]>> { 61 try { 62 const collections = Array.from(this.collections.values()).filter( 63 (collection) => 64 collection.cardLinks.some( 65 (link) => link.cardId.getStringValue() === cardId.getStringValue(), 66 ), 67 ); 68 return ok(collections.map((collection) => this.clone(collection))); 69 } catch (error) { 70 return err(error as Error); 71 } 72 } 73 74 async findByCuratorIdContainingCard( 75 authorId: CuratorId, 76 cardId: CardId, 77 ): Promise<Result<Collection[]>> { 78 try { 79 const collections = Array.from(this.collections.values()).filter( 80 (collection) => 81 collection.authorId.value === authorId.value && 82 collection.cardLinks.some( 83 (link) => link.cardId.getStringValue() === cardId.getStringValue(), 84 ), 85 ); 86 return ok(collections.map((collection) => this.clone(collection))); 87 } catch (error) { 88 return err(error as Error); 89 } 90 } 91 92 async save(collection: Collection): Promise<Result<void>> { 93 try { 94 this.collections.set( 95 collection.collectionId.getStringValue(), 96 this.clone(collection), 97 ); 98 return ok(undefined); 99 } catch (error) { 100 return err(error as Error); 101 } 102 } 103 104 async delete(collectionId: CollectionId): Promise<Result<void>> { 105 try { 106 this.collections.delete(collectionId.getStringValue()); 107 return ok(undefined); 108 } catch (error) { 109 return err(error as Error); 110 } 111 } 112 113 // Helper methods for testing 114 public clear(): void { 115 this.collections.clear(); 116 } 117 118 public getStoredCollection(id: CollectionId): Collection | undefined { 119 return this.collections.get(id.getStringValue()); 120 } 121 122 public getAllCollections(): Collection[] { 123 return Array.from(this.collections.values()).map((collection) => 124 this.clone(collection), 125 ); 126 } 127}