Skip to content

Commit

Permalink
feat: Get the first model from a query.
Browse files Browse the repository at this point in the history
  • Loading branch information
Artmann committed Jul 12, 2020
1 parent 7f5caa3 commit 0a624f6
Show file tree
Hide file tree
Showing 2 changed files with 184 additions and 114 deletions.
262 changes: 159 additions & 103 deletions src/base-model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,45 +40,6 @@ describe('BaseModel', () => {
});
});

describe('find', () => {

it('returns null for non existing documents.', async() => {
const book = await Book.find('abc-123');

expect(collection.findOne).toHaveBeenCalledWith({
_id: 'abc-123'
});

expect(book).toBeNull();
});

it('finds a document by id.', async() => {
collection.findOne.mockResolvedValue({
_id: new ObjectId('5f0aeaeacff57e3ec676b340'),
authorId: 'author-1',
createdAt: 1594552340652,
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
});

const book = await Book.find('5f0aeaeacff57e3ec676b340');

expect(collection.findOne).toHaveBeenCalledWith({
_id: '5f0aeaeacff57e3ec676b340'
});

expect(book).toEqual({
authorId: 'author-1',
createdAt: 1594552340652,
id: '5f0aeaeacff57e3ec676b340',
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
});
});
});

describe('all', () => {
it('finds all documets.', async() => {
const cursor = createCursor([
Expand Down Expand Up @@ -139,70 +100,6 @@ describe('BaseModel', () => {
});
});

describe('where', () => {
it ('finds all documets that matches a query', async() => {
const cursor = createCursor([
{
_id: new ObjectId('5f0aeaeacff57e3ec676b340'),
authorId: 'author-1',
createdAt: 1594552340652,
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
},
{
_id: new ObjectId('5f0aefba348289a81889a920'),
authorId: 'author-1',
createdAt: 1594552346653,
isbn: '978-3-16-148410-1',
title: 'Esix for dummies 2',
updatedAt: 0
}
]);

collection.find.mockReturnValue(cursor);

const books = await Book.where('authorId', 'author-1').get();

expect(collection.find).toHaveBeenCalledWith({
authorId: 'author-1'
});

expect(books).toEqual([
{
authorId: 'author-1',
createdAt: 1594552340652,
id: '5f0aeaeacff57e3ec676b340',
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
},
{
authorId: 'author-1',
createdAt: 1594552346653,
id: '5f0aefba348289a81889a920',
isbn: '978-3-16-148410-1',
title: 'Esix for dummies 2',
updatedAt: 0
}
]);
});

it('returns an empty array if there is no matching documents.', async() => {
const cursor = createCursor([]);

collection.find.mockReturnValue(cursor);

const books = await Book.where('authorId', 'author-2').get();

expect(collection.find).toHaveBeenCalledWith({
authorId: 'author-2'
});

expect(books).toEqual([]);
});
});

describe('create', () => {
it('creates a new Model.', async() => {
const dateSpy = jest.spyOn(Date, 'now');
Expand Down Expand Up @@ -290,4 +187,163 @@ describe('BaseModel', () => {
});
});
});

describe('find', () => {

it('returns null for non existing documents.', async() => {
collection.findOne.mockReturnValue(null);

const book = await Book.find('abc-123');

expect(collection.findOne).toHaveBeenCalledWith({
_id: 'abc-123'
});

expect(book).toBeNull();
});

it('finds a document by id.', async() => {
collection.findOne.mockResolvedValue({
_id: new ObjectId('5f0aeaeacff57e3ec676b340'),
authorId: 'author-1',
createdAt: 1594552340652,
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
});

const book = await Book.find('5f0aeaeacff57e3ec676b340');

expect(collection.findOne).toHaveBeenCalledWith({
_id: '5f0aeaeacff57e3ec676b340'
});

expect(book).toEqual({
authorId: 'author-1',
createdAt: 1594552340652,
id: '5f0aeaeacff57e3ec676b340',
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
});
});
});

describe('first', () => {
it('returns the first model.', async() => {
const cursor = createCursor([
{
_id: new ObjectId('5f0aeaeacff57e3ec676b340'),
authorId: 'author-1',
createdAt: 1594552340652,
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
},
{
_id: new ObjectId('5f0aefba348289a81889a920'),
authorId: 'author-1',
createdAt: 1594552346653,
isbn: '978-3-16-148410-1',
title: 'Esix for dummies 2',
updatedAt: 0
}
]);

collection.find.mockReturnValue(cursor);

const book = await Book.where('authorId', 'author-1').first();

expect(collection.find).toHaveBeenCalledWith({
authorId: 'author-1'
});

expect(book).toEqual({
authorId: 'author-1',
createdAt: 1594552340652,
id: '5f0aeaeacff57e3ec676b340',
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
});
});

it('returns null if there is no matching models.', async() => {
const cursor = createCursor([]);

collection.find.mockReturnValue(cursor);

const book = await Book.where('authorId', 'author-1').first();

expect(collection.find).toHaveBeenCalledWith({
authorId: 'author-1'
});

expect(book).toBeNull();
});
});

describe('where', () => {
it ('finds all documets that matches a query', async() => {
const cursor = createCursor([
{
_id: new ObjectId('5f0aeaeacff57e3ec676b340'),
authorId: 'author-1',
createdAt: 1594552340652,
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
},
{
_id: new ObjectId('5f0aefba348289a81889a920'),
authorId: 'author-1',
createdAt: 1594552346653,
isbn: '978-3-16-148410-1',
title: 'Esix for dummies 2',
updatedAt: 0
}
]);

collection.find.mockReturnValue(cursor);

const books = await Book.where('authorId', 'author-1').get();

expect(collection.find).toHaveBeenCalledWith({
authorId: 'author-1'
});

expect(books).toEqual([
{
authorId: 'author-1',
createdAt: 1594552340652,
id: '5f0aeaeacff57e3ec676b340',
isbn: '978-3-16-148410-0',
title: 'Esix for dummies',
updatedAt: 0
},
{
authorId: 'author-1',
createdAt: 1594552346653,
id: '5f0aefba348289a81889a920',
isbn: '978-3-16-148410-1',
title: 'Esix for dummies 2',
updatedAt: 0
}
]);
});

it('returns an empty array if there is no matching documents.', async() => {
const cursor = createCursor([]);

collection.find.mockReturnValue(cursor);

const books = await Book.where('authorId', 'author-2').get();

expect(collection.find).toHaveBeenCalledWith({
authorId: 'author-2'
});

expect(books).toEqual([]);
});
});
});
36 changes: 25 additions & 11 deletions src/query-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ export default class QueryBuilder<T> {
return this.createInstance(document);
}

async first(): Promise<T | null> {
const models = await this.execute();

if (models.length === 0) {
return null;
}

return models[0];
}

async get(): Promise<T[]> {
return this.execute();
}

where(query: Query): QueryBuilder<T>;
where(key: string, value: any): QueryBuilder<T>;
where(queryOrKey: Query | string, value?: any): QueryBuilder<T> {
Expand All @@ -59,17 +73,6 @@ export default class QueryBuilder<T> {
return this;
}

async get(): Promise<T[]> {
const collection = await this.getCollection();
const documents = await collection.find(this.query).toArray();

const records = documents
.filter(document => document)
.map((document): T => this.createInstance(document));

return records;
}

private createInstance<T>(document: Document): T {
const instance = new this.ctor() as any;

Expand Down Expand Up @@ -129,4 +132,15 @@ export default class QueryBuilder<T> {

return database;
}

private async execute(): Promise<T[]> {
const collection = await this.getCollection();
const documents = await collection.find(this.query).toArray();

const records = documents
.filter(document => document)
.map((document): T => this.createInstance(document));

return records;
}
}

0 comments on commit 0a624f6

Please sign in to comment.