This repository has no description
0

Configure Feed

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

semble / src / modules / cards / tests / utils / InMemoryCardRepository.ts
3.9 kB 138 lines
1import { Result, ok, err } from '../../../../shared/core/Result'; 2import { ICardRepository } from '../../domain/ICardRepository'; 3import { Card } from '../../domain/Card'; 4import { CardId } from '../../domain/value-objects/CardId'; 5import { CuratorId } from '../../domain/value-objects/CuratorId'; 6import { URL } from '../../domain/value-objects/URL'; 7 8export class InMemoryCardRepository implements ICardRepository { 9 private static instance: InMemoryCardRepository; 10 private cards: Map<string, Card> = new Map(); 11 private shouldFail: boolean = false; 12 private shouldFailSave: boolean = false; 13 14 private constructor() {} 15 16 public static getInstance(): InMemoryCardRepository { 17 if (!InMemoryCardRepository.instance) { 18 InMemoryCardRepository.instance = new InMemoryCardRepository(); 19 } 20 return InMemoryCardRepository.instance; 21 } 22 23 private clone(card: Card): Card { 24 // Simple clone - in a real implementation you'd want proper deep cloning 25 const cardResult = Card.create( 26 { 27 curatorId: card.props.curatorId, 28 type: card.type, 29 content: card.content, 30 parentCardId: card.parentCardId, 31 viaCardId: card.viaCardId, 32 url: card.url, 33 publishedRecordId: card.publishedRecordId, 34 libraryMemberships: card.libraryMemberships, 35 libraryCount: card.libraryCount, 36 createdAt: card.createdAt, 37 updatedAt: card.updatedAt, 38 }, 39 card.id, 40 ); 41 42 if (cardResult.isErr()) { 43 throw new Error(`Failed to clone card: ${cardResult.error.message}`); 44 } 45 46 return cardResult.value; 47 } 48 49 async findById(id: CardId): Promise<Result<Card | null>> { 50 if (this.shouldFail) { 51 return err(new Error('Simulated find failure')); 52 } 53 try { 54 const card = this.cards.get(id.getStringValue()); 55 return ok(card ? this.clone(card) : null); 56 } catch (error) { 57 return err(error as Error); 58 } 59 } 60 61 async findUsersUrlCardByUrl( 62 url: URL, 63 curatorId: CuratorId, 64 ): Promise<Result<Card | null>> { 65 try { 66 const card = Array.from(this.cards.values()).find( 67 (card) => 68 card.type.value === 'URL' && 69 card.url?.value === url.value && 70 card.props.curatorId.equals(curatorId), 71 ); 72 return ok(card ? this.clone(card) : null); 73 } catch (error) { 74 return err(error as Error); 75 } 76 } 77 78 async findUsersNoteCardByUrl( 79 url: URL, 80 curatorId: CuratorId, 81 ): Promise<Result<Card | null>> { 82 try { 83 const card = Array.from(this.cards.values()).find( 84 (card) => 85 card.type.value === 'NOTE' && 86 card.url?.value === url.value && 87 card.props.curatorId.equals(curatorId), 88 ); 89 return ok(card ? this.clone(card) : null); 90 } catch (error) { 91 return err(error as Error); 92 } 93 } 94 95 async save(card: Card): Promise<Result<void>> { 96 if (this.shouldFailSave || this.shouldFail) { 97 return err(new Error('Simulated save failure')); 98 } 99 try { 100 this.cards.set(card.cardId.getStringValue(), this.clone(card)); 101 return ok(undefined); 102 } catch (error) { 103 return err(error as Error); 104 } 105 } 106 107 async delete(cardId: CardId): Promise<Result<void>> { 108 try { 109 this.cards.delete(cardId.getStringValue()); 110 return ok(undefined); 111 } catch (error) { 112 return err(error as Error); 113 } 114 } 115 116 setShouldFail(shouldFail: boolean): void { 117 this.shouldFail = shouldFail; 118 } 119 120 setShouldFailSave(shouldFailSave: boolean): void { 121 this.shouldFailSave = shouldFailSave; 122 } 123 124 // Helper methods for testing 125 public clear(): void { 126 this.cards.clear(); 127 this.shouldFail = false; 128 this.shouldFailSave = false; 129 } 130 131 public getStoredCard(id: CardId): Card | undefined { 132 return this.cards.get(id.getStringValue()); 133 } 134 135 public getAllCards(): Card[] { 136 return Array.from(this.cards.values()).map((card) => this.clone(card)); 137 } 138}