import { Aggregate , Apply , PersistedSnapshot } from '@centsideas/event-sourcing' ; import { IdeaId , UserId , Timestamp } from '@centsideas/types' ; import { PersistedEvent } from '@centsideas/models' ; import * as Errors from './idea.errors' ; import { IdeaTitle } from './idea-title' ; import { IdeaTags } from './idea-tags' ; import { IdeaDescription } from './idea-description' ; import { IdeaRenamed } from './idea-renamed' ; import { IdeaCreated } from './idea-created' ; import { IdeaDescriptionEdited } from './idea-description-edited' ; import { IdeaTagsAdded } from './idea-tags-added' ; import { IdeaTagsRemoved } from './idea-tags-removed' ; import { IdeaPublished } from './idea-published' ; import { IdeaDeleted } from './idea-deleted' ; export interface SerializedIdea { id : string ; userId : string ; tags : string [ ] ; title : string | undefined ; description : string | undefined ; publishedAt : string | undefined ; deletedAt : string | undefined ; } export class Idea extends Aggregate < SerializedIdea > { protected id ! : IdeaId ; private userId ! : UserId ; private tags = IdeaTags . empty ( ) ; private title : IdeaTitle | undefined ; private description : IdeaDescription | undefined ; private publishedAt : Timestamp | undefined ; private deletedAt : Timestamp | undefined ; static buildFrom ( events , snapshot ? ) { const idea = new Idea ( ) ; if ( snapshot ) idea . applySnapshot ( snapshot , events ) ; else idea . replay ( events ) ; return idea ; } protected deserialize ( data ) { this . id = IdeaId . fromString ( data . id ) ; this . userId = UserId . fromString ( data . userId ) ; this . tags = IdeaTags . fromArray ( data . tags ) ; this . title = data . title ? IdeaTitle . fromString ( data . title ) : undefined ; this . description = data . description ? IdeaDescription . fromString ( data . description ) : undefined ; this . publishedAt = data . publishedAt ? Timestamp . fromString ( data . publishedAt ) : undefined ; this . deletedAt = data . deletedAt ? Timestamp . fromString ( data . deletedAt ) : undefined ; } protected serialize ( ) { return { id : this . id . toString ( ) , userId : this . userId . toString ( ) , tags : this . tags . toArray ( ) , title : this . title ?. toString ( ) , description : this . description ?. toString ( ) , publishedAt : this . publishedAt ?. toString ( ) , deletedAt : this . deletedAt ?. toString ( ) , } ; } static create ( id , user , createdAt ) { const idea = new Idea ( ) ; idea . raise ( new IdeaCreated ( id , user , createdAt ) ) ; return idea ; } rename ( title , user ) { this . checkGeneralConditions ( user ) ; if ( this . title ?. toString ( ) === title . toString ( ) ) return ; this . raise ( new IdeaRenamed ( title ) ) ; } editDescription ( description , user ) { this . checkGeneralConditions ( user ) ; if ( this . description ?. toString ( ) === description . toString ( ) ) return ; this . raise ( new IdeaDescriptionEdited ( description ) ) ; } updateTags ( tags , user ) { this . checkGeneralConditions ( user ) ; const { added , removed } = this . tags . findDifference ( tags ) ; if ( added . toArray ( ) . length ) this . raise ( new IdeaTagsAdded ( added ) ) ; if ( removed . toArray ( ) . length ) this . raise ( new IdeaTagsRemoved ( removed ) ) ; } publish ( publishedAt , user ) { this . checkGeneralConditions ( user ) ; if ( this . publishedAt ) return ; if ( ! this . title ) throw new Errors . IdeaTitleRequired ( this . id , user ) ; this . raise ( new IdeaPublished ( publishedAt ) ) ; } delete ( deletedAt , user ) { this . checkGeneralConditions ( user ) ; this . raise ( new IdeaDeleted ( deletedAt ) ) ; } private checkGeneralConditions ( user ) { if ( ! this . userId . equals ( user ) ) throw new Errors . NoPermissionToAccessIdea ( this . id , user ) ; if ( this . deletedAt ) throw new Errors . IdeaAlreadyDeleted ( this . id , user ) ; } @ Apply ( IdeaCreated ) protected created ( event ) { this . id = event . id ; this . userId = event . userId ; } @ Apply ( IdeaRenamed ) protected renamed ( event ) { this . title = event . title ; } @ Apply ( IdeaDescriptionEdited ) protected descriptionEdited ( event ) { this . description = event . description ; } @ Apply ( IdeaTagsAdded ) protected tagsAdded ( event ) { this . tags . add ( event . tags ) ; } @ Apply ( IdeaTagsRemoved ) protected tagsRemoved ( event ) { this . tags . remove ( event . tags ) ; } @ Apply ( IdeaPublished ) protected published ( event ) { this . publishedAt = event . publishedAt ; } @ Apply ( IdeaDeleted ) protected deleted ( event ) { this . deletedAt = event . deletedAt ; } }