Skip to content

Commit

Permalink
feat(core): add getByIdOrThrow on AggregateRepo
Browse files Browse the repository at this point in the history
  • Loading branch information
gtoselli committed Mar 30, 2024
1 parent 9d6ab6c commit ffb1238
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-moles-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fizzbuds/ddd-toolkit": patch
---

add getByIdOrThrow to IAggregateRepo
6 changes: 6 additions & 0 deletions packages/ddd-toolkit/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ export class RepoHookError extends Error {
super(message);
}
}

export class AggregateNotFoundError extends Error {
constructor(message: string) {
super(message);
}
}
18 changes: 15 additions & 3 deletions packages/ddd-toolkit/src/repo/mongo-aggregate-repo.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { IRepoHooks } from './repo-hooks';
import { Collection, Document, MongoClient } from 'mongodb';
import { Collection, Document, MongoClient, WithId } from 'mongodb';
import { ISerializer } from './serializer.interface';
import { merge } from 'lodash';
import { DuplicatedIdError, OptimisticLockError, RepoHookError } from '../errors';
import { AggregateNotFoundError, DuplicatedIdError, OptimisticLockError, RepoHookError } from '../errors';
import { ILogger } from '../logger';
import { IInit } from '../init.interface';

export interface IAggregateRepo<A> {
// TODO add id as a generic type
getById: (id: string) => Promise<WithVersion<A> | null>;
getByIdOrThrow: (id: string) => Promise<WithVersion<A>>;
save: (aggregate: A) => Promise<void>;
}

Expand All @@ -23,6 +24,7 @@ const MONGODB_UNIQUE_INDEX_CONSTRAINT_ERROR = 11000;

export class MongoAggregateRepo<A, AM extends DocumentWithId> implements IAggregateRepo<A>, IInit {
protected readonly collection: Collection<AM>;

constructor(
protected readonly serializer: ISerializer<A, AM>,
protected readonly mongoClient: MongoClient,
Expand Down Expand Up @@ -94,11 +96,21 @@ export class MongoAggregateRepo<A, AM extends DocumentWithId> implements IAggreg
}
}

// TODO evaluate to implement getOrThrow
async getById(id: string): Promise<WithVersion<A> | null> {
const aggregateModel = await this.collection.findOne({ id: id } as any);
this.logger.debug(`Retrieving aggregate ${id}. Found: ${JSON.stringify(aggregateModel)}`);
if (!aggregateModel) return null;

return this.modelToAggregateWithVersion(aggregateModel);
}

async getByIdOrThrow(id: string): Promise<WithVersion<A>> {
const aggregate = await this.getById(id);
if (!aggregate) throw new AggregateNotFoundError(`Aggregate ${id} not found.`);
return aggregate;

Check warning on line 110 in packages/ddd-toolkit/src/repo/mongo-aggregate-repo.ts

View check run for this annotation

Codecov / codecov/patch

packages/ddd-toolkit/src/repo/mongo-aggregate-repo.ts#L110

Added line #L110 was not covered by tests
}

private modelToAggregateWithVersion(aggregateModel: WithId<AM>): WithVersion<A> {
const aggregate = this.serializer.modelToAggregate(aggregateModel as AM);
return merge<A, { __version: number }>(aggregate, { __version: aggregateModel.__version });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MongoAggregateRepo } from '../mongo-aggregate-repo';
import { MongoMemoryReplSet } from 'mongodb-memory-server';
import { MongoClient } from 'mongodb';
import { TestAggregate, TestModel, TestSerializer } from './example.serializer';
import { AggregateNotFoundError } from '../../errors';

describe('MongoAggregateRepo MongoDB Integration', () => {
let mongodb: MongoMemoryReplSet;
Expand Down Expand Up @@ -39,7 +40,7 @@ describe('MongoAggregateRepo MongoDB Integration', () => {
});

describe('Save and Get', () => {
describe('Given an aggregate', () => {
describe('Given an existing aggregate', () => {
describe('When saving', () => {
const id1 = 'id1';
beforeEach(async () => {
Expand All @@ -54,6 +55,22 @@ describe('MongoAggregateRepo MongoDB Integration', () => {
});
});
});

describe('Given an un-existing aggregate', () => {
describe('When getById', () => {
it('should return null', async () => {
expect(await aggregateRepo.getById('not-existing-id')).toBeNull();
});
});

describe('When getByIdOrThrow', () => {
it('should throw AggregateNotFoundError', async () => {
await expect(() => aggregateRepo.getByIdOrThrow('not-existing-id')).rejects.toThrowError(
AggregateNotFoundError,
);
});
});
});
});

describe('Optimistic Lock', () => {
Expand Down

0 comments on commit ffb1238

Please sign in to comment.