diff --git a/libs/event-emitter/src/event-emitter.module.ts b/libs/event-emitter/src/event-emitter.module.ts index 3104f64..f2cc727 100644 --- a/libs/event-emitter/src/event-emitter.module.ts +++ b/libs/event-emitter/src/event-emitter.module.ts @@ -8,6 +8,7 @@ import { ConfigModule } from '@nestjs/config'; import { RedmineDataLoader } from './redmine-data-loader/redmine-data-loader'; import { MainController } from './main/main.controller'; import { ModuleParams } from './models/module-params'; +import { RedmineIssuesCacheWriterService } from './issue-cache-writer/redmine-issues-cache-writer.service'; import { CouchDb } from './couchdb-datasources/couchdb'; import { Users } from './couchdb-datasources/users'; import { Issues } from './couchdb-datasources/issues'; @@ -27,6 +28,7 @@ export class EventEmitterModule { EventEmitterService, RedmineEventsGateway, RedmineDataLoader, + RedmineIssuesCacheWriterService, CouchDb, Users, Issues, @@ -35,6 +37,7 @@ export class EventEmitterModule { EventEmitterService, RedmineEventsGateway, RedmineDataLoader, + RedmineIssuesCacheWriterService, CouchDb, Users, Issues, diff --git a/libs/event-emitter/src/issue-cache-writer/redmine-issues-cache-writer.service.ts b/libs/event-emitter/src/issue-cache-writer/redmine-issues-cache-writer.service.ts new file mode 100644 index 0000000..8e97718 --- /dev/null +++ b/libs/event-emitter/src/issue-cache-writer/redmine-issues-cache-writer.service.ts @@ -0,0 +1,87 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { RedmineTypes } from 'libs/redmine-types'; +import nano from 'nano'; +import { Subject } from 'rxjs'; +import { Issues } from '../couchdb-datasources/issues'; +import { SaveResponse } from '../models/save-response'; + +@Injectable() +export class RedmineIssuesCacheWriterService { + private logger = new Logger(RedmineIssuesCacheWriterService.name); + + subject = new Subject(); + + constructor(private issues: Issues) {} + + async saveIssue(issue: RedmineTypes.Issue): Promise { + this.logger.debug( + `Saving issue ${issue?.id || '-'} - ${ + issue?.subject || '-' + }, issue data = ${JSON.stringify(issue)}`, + ); + const id = Number(issue['id']); + let prevIssue: (nano.DocumentGetResponse & RedmineTypes.Issue) | null; + const issueDb = await Issues.getDatasource(); + if (!issueDb) { + console.error(`CouchDb datasource must defined`); + } + try { + prevIssue = await issueDb.get(String(id)); + } catch (ex) { + prevIssue = null; + } + let newIssue: nano.DocumentGetResponse & RedmineTypes.Issue; + if (!prevIssue) { + newIssue = { ...(issue as any) }; + newIssue._id = String(id); + await issueDb.insert(newIssue); + } else { + newIssue = { ...(issue as any) }; + newIssue._id = String(id); + newIssue._rev = prevIssue._rev; + await issueDb.insert(newIssue); + } + const res = { + prev: prevIssue, + current: newIssue, + journalsDiff: this.getJournalsDiff(prevIssue, newIssue), + }; + this.logger.debug( + `Saving issue success ${issue?.id || '-'} - ${issue?.subject || '-'}`, + ); + this.subject.next(res); + return res; + } + + getJournalsDiff( + prev: (nano.DocumentGetResponse & RedmineTypes.Issue) | null, + current: nano.DocumentGetResponse & RedmineTypes.Issue, + ): RedmineTypes.Journal[] { + if ( + (!prev || !prev.journals || prev.journals.length === 0) && + current?.journals + ) { + return current.journals; + } else if (prev?.journals && current?.journals) { + return this.calcJournalsDiff(prev?.journals, current?.journals); + } + return []; + } + + private calcJournalsDiff( + prev: RedmineTypes.Journal[], + current: RedmineTypes.Journal[], + ): RedmineTypes.Journal[] { + const res: RedmineTypes.Journal[] = []; + + const prevIds = prev.map((item) => item.id); + + for (let i = 0; i < current.length; i++) { + const currentItem = current[i]; + if (!prevIds.includes(currentItem.id)) { + res.push(currentItem); + } + } + return res; + } +}