Skip to content

Commit

Permalink
Development (#484)
Browse files Browse the repository at this point in the history
* include restaurant information as part of the menu response (#471)

* include restaurant information as part of the menu response

* fix build errors

* fix build errors

---------

Co-authored-by: Olasunkanmi Oyinlola <olasunkanmioyinlola@Olasunkanmis-Mac-mini.local>

* 349 place order (#473)

* include restaurant information as part of the menu response

* fix build errors

* fix build errors

* fix the create order flow, from frontend to backend

---------

Co-authored-by: Olasunkanmi Oyinlola <olasunkanmioyinlola@Olasunkanmis-Mac-mini.local>

* 349 place order (#476)

* 349 place order (#478)

* include restaurant information as part of the menu response

* fix build errors

* fix build errors

* fix the create order flow, from frontend to backend

* place order, add success animation and clear local storage if the cart has been filled for an hr and more

* fix build errors

* fix build errors

* move the implementation of adding expiry to cart to addItemToCart handler

* fix issues with creating notes when none was passwd

* npm audit to upgrade packages with issues

---------

Co-authored-by: Olasunkanmi Oyinlola <olasunkanmioyinlola@Olasunkanmis-Mac-mini.local>

* display api error message

* display api error message

* save the ordersummary of each order, to recreate the order in order history

* include mogoDB transaction during order creation

* fix build error

---------

Co-authored-by: Olasunkanmi Oyinlola <olasunkanmioyinlola@Olasunkanmis-Mac-mini.local>
  • Loading branch information
olasunkanmi-SE and Olasunkanmi Oyinlola committed Jan 21, 2024
1 parent 7166a26 commit 7d29d4c
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Injectable } from '@nestjs/common';
import { HttpStatus, Injectable } from '@nestjs/common';
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
import { Connection, Model } from 'mongoose';
import { CartItem } from 'src/cart/cart-item';
import { Result } from 'src/domain';
import { GenericDocumentRepository } from 'src/infrastructure/database';
import { throwApplicationError } from 'src/infrastructure/utilities/exception-instance';
import { CartItemMapper } from './../../../cart/cart-item.mapper';
import { ICartItemRepository } from './interfaces/cart-item-repository.interface';
import { CartItemDataModel, CartItemDocument } from './schemas/cartItem.schema';
Expand All @@ -22,10 +24,20 @@ export class CartItemRepository
this.cartItemMapper = cartItemMapper;
}

async updateCartItemSelectedItems(cartItems: CartItem[]): Promise<void> {
const document = cartItems.map((doc) => this.cartItemMapper.toPersistence(doc));
document.forEach((item) => {
this.updateOne({ _id: item._id }, { selectedItems: item.selectedItems });
});
async updateCartItemSelectedItems(cartItems: CartItem[]): Promise<Result<CartItem[]>> {
try {
const document = cartItems.map((doc) => this.cartItemMapper.toPersistence(doc));
const selectedItemsToUpdate = document.map((doc) => ({ _id: doc._id, selectedItems: doc.selectedItems }));
const result = await this.updateMany(
{ _id: { $in: document.map((doc) => doc._id) } },
{ $set: { selectedItems: selectedItemsToUpdate } },
);
if (!result.isSuccess) {
throwApplicationError(HttpStatus.BAD_REQUEST, '');
}
return result;
} catch (error) {
console.error('an error occured', error);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { CartItem } from 'src/cart/cart-item';
import { IGenericDocument } from 'src/infrastructure/database';
import { CartItemDocument } from '../schemas/cartItem.schema';
import { Result } from 'src/domain';
import { ClientSession } from 'mongoose';

export interface ICartItemRepository extends IGenericDocument<CartItem, CartItemDocument> {
updateCartItemSelectedItems(cartItems: CartItem[]): Promise<void>;
updateCartItemSelectedItems(cartItems: CartItem[], options?: { session: ClientSession }): Promise<Result<CartItem[]>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { OrderDataModel, OrderDocument } from '../schemas/order.schema';
import { IGenericDocument } from 'src/infrastructure/database';
import { Result } from 'src/domain';
import { CreateCartItemsDTO } from 'src/order/dto/create-order.dto';
import { ClientSession } from 'mongoose';

export interface IOrderRepository extends IGenericDocument<Order, OrderDocument> {
createOrder(order: OrderDataModel): Promise<Result<Order>>;
createOrder(order: OrderDataModel, options?: { session: ClientSession }): Promise<Result<Order>>;
getDuplicateOrder(type: string, singleclientId: string, cartItems: CreateCartItemsDTO[]): Promise<boolean>;
getOrders(): Promise<Result<Order[]>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ export interface IGenericDocument<TEntity, T> {

create(document: any, options?: SaveOptions): Promise<Result<TEntity>>;

findOneAndUpdate(filterQuery: FilterQuery<T>, update: UpdateQuery<T>): Promise<Result<TEntity | null>>;
findOneAndUpdate(
filterQuery: FilterQuery<T>,
update: UpdateQuery<T>,
options?: { session: ClientSession },
): Promise<Result<TEntity | null>>;

upsert(filterQuery: FilterQuery<T>, document: Partial<T>): Promise<Result<TEntity | null>>;
upsert(filterQuery: FilterQuery<T>, document: Partial<T>, options?: QueryOptions<T>): Promise<Result<TEntity | null>>;

deleteMany(filterQuery: FilterQuery<T>): Promise<boolean>;

Expand All @@ -31,4 +35,8 @@ export interface IGenericDocument<TEntity, T> {
objectIdToString(objectId: Types.ObjectId): string;

stringToObjectId(prop: string): Types.ObjectId;

updateMany(query: FilterQuery<T>, updateBody: UpdateQuery<T>, options?: QueryOptions<T>): Promise<Result<TEntity[]>>;

insertManyWithSession(docs: any, options?: QueryOptions<T>): Promise<Result<Types.ObjectId[]>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export abstract class GenericDocumentRepository<TEntity, T extends Document> imp
}

async create(document: any, options?: SaveOptions): Promise<Result<TEntity>> {
const doc = this.createDocument(document);
const doc = this.createDocument(document, options);
const result = (await (await doc.save(options)).toJSON()) as T;
if (!result) {
return Result.fail('An Error occured, unable to save document in the db', HttpStatus.INTERNAL_SERVER_ERROR);
Expand All @@ -105,23 +105,39 @@ export abstract class GenericDocumentRepository<TEntity, T extends Document> imp
return Result.ok(entity);
}

async findOneAndUpdate(filterQuery: FilterQuery<T>, update: UpdateQuery<T>): Promise<Result<TEntity | null>> {
const result = await this.DocumentModel.findByIdAndUpdate(filterQuery, update, {
async findOneAndUpdate(
filterQuery: FilterQuery<T>,
update: UpdateQuery<T>,
options?: { session: ClientSession },
): Promise<Result<TEntity | null>> {
const queryOptions: any = {
new: true,
});
};
if (options?.session) {
queryOptions.session = options.session;
}
const result = await this.DocumentModel.findByIdAndUpdate(filterQuery, update, queryOptions);
if (!result) {
return Result.fail('An Error occured, unable to update the database', HttpStatus.INTERNAL_SERVER_ERROR);
}
const entity = this.mapper.toDomain(result);
return Result.ok(entity);
}

async upsert(filterQuery: FilterQuery<T>, document: Partial<T>): Promise<Result<TEntity | null>> {
const result = await this.DocumentModel.findOneAndUpdate(filterQuery, document, {
async upsert(
filterQuery: FilterQuery<T>,
document: Partial<T>,
options?: { session?: ClientSession },
): Promise<Result<TEntity | null>> {
const queryOption: any = {
lean: true,
upsert: true,
new: true,
});
};
if (options?.session) {
queryOption.session = options.session;
}
const result = await this.DocumentModel.findOneAndUpdate(filterQuery, document, { session: options.session });

if (!result) {
return Result.fail('Unable to update the database', HttpStatus.INTERNAL_SERVER_ERROR);
Expand Down Expand Up @@ -158,6 +174,26 @@ export abstract class GenericDocumentRepository<TEntity, T extends Document> imp
}
}

async insertManyWithSession(docs: any, options?: QueryOptions<T>): Promise<Result<Types.ObjectId[]>> {
try {
let documentIds: Types.ObjectId[];
const documentsToSave = docs.map((doc) => this.createDocument(doc));
const documents = await this.DocumentModel.insertMany(documentsToSave, {
rawResult: true,
});
if (documents.insertedCount < docs.length) {
throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to insert documents into the database');
}
const insertedDocIds: any = Object.values(documents.insertedIds);
if (insertedDocIds?.length) {
documentIds = insertedDocIds.map((id) => this.stringToObjectId(id));
}
return Result.ok(documentIds);
} catch (error) {
console.error(error);
}
}

async updateOne(filter: any, query: any): Promise<Result<TEntity>> {
try {
const document = await this.DocumentModel.updateOne(filter, { $set: query });
Expand All @@ -171,14 +207,25 @@ export abstract class GenericDocumentRepository<TEntity, T extends Document> imp
}
}

async updateMany(query: FilterQuery<T>, updateBody: UpdateQuery<T>): Promise<Result<TEntity[]>> {
async updateMany(
query: FilterQuery<T>,
updateBody: UpdateQuery<T>,
options?: { session?: ClientSession },
): Promise<Result<TEntity[]>> {
try {
const saved = await this.DocumentModel.updateMany(query, updateBody, {
const updateOptions: QueryOptions<T> = {
multi: true,
});
};

if (options?.session) {
updateOptions.session = options.session;
}

const saved = await this.DocumentModel.updateMany(query, updateBody, updateOptions);
if (saved.matchedCount < 1) {
throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, 'Unable to update documents into the database');
}

const updatedDocuments = await this.DocumentModel.find(query);
const entities: TEntity[] = updatedDocuments.map((doc) => this.mapper.toDomain(doc));
return Result.ok(entities);
Expand All @@ -187,10 +234,15 @@ export abstract class GenericDocumentRepository<TEntity, T extends Document> imp
}
}

createDocument(document: any) {
return new this.DocumentModel({
private createDocument(document: any, options?: { session?: ClientSession }) {
const doc = new this.DocumentModel({
...document,
_id: new Types.ObjectId(),
});

if (options?.session) {
doc.$session(options.session);
}
return doc;
}
}
14 changes: 11 additions & 3 deletions backend/src/order/order.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ export class OrderService implements IOrderService {
const orderWithCartItems = await this.orderRepository.upsert(
{ _id: orderId },
this.orderMapper.toPersistence(savedOrder),
{ session },
);
if (orderWithCartItems.isSuccess === false) {
if (!orderWithCartItems.isSuccess) {
throwApplicationError(HttpStatus.INTERNAL_SERVER_ERROR, `Error while creating order`);
}

Expand All @@ -122,7 +123,7 @@ export class OrderService implements IOrderService {
}),
);
const selectedCartItemsDataModel = selectedItems.map((item) => this.selectedItemMapper.toPersistence(item));
const insertedItems: Result<SelectedCartItem[]> = await this.selectedCartItemRepository.insertMany(
const insertedItems: Result<Types.ObjectId[]> = await this.selectedCartItemRepository.insertManyWithSession(
selectedCartItemsDataModel,
);
if (!insertedItems.isSuccess) {
Expand All @@ -131,7 +132,14 @@ export class OrderService implements IOrderService {
const notes = await this.createOrderNotes(cartItems, orderId);
const notesToSave: OrderNote[] = notes || [];
const response: IOrderResponseDTO | undefined = OrderParser.createOrderResponse(savedOrder, notesToSave);
const savedSelectedItems = insertedItems.getValue();
const savedSelectedItemIds = insertedItems.getValue();
let savedSelectedItems: SelectedCartItem[];
if (savedSelectedItemIds.length) {
const result = await this.selectedCartItemRepository.find({ _id: { $in: savedSelectedItemIds } });
if (result.isSuccess) {
savedSelectedItems = result.getValue();
}
}
const savedItemsMap = savedSelectedItems.reduce((map, item) => {
const cartItemIdToString = this.cartItemRepository.objectIdToString(item.cartItemId);
!map.has(cartItemIdToString) ? map.set(cartItemIdToString, [item]) : map.get(cartItemIdToString).push(item);
Expand Down

0 comments on commit 7d29d4c

Please sign in to comment.