Skip to content

Commit

Permalink
Adding pagination on orders-api when we getting all orders (#152)
Browse files Browse the repository at this point in the history
* Adding pagination on orders-api when we getting all orders

* fixing the unit tests

* fixing the fetchAll not returning all items

* fixing checkout consumer issue: still some issues

* Orders page in the dashboard app

- order-api: added new type OrdersDto
  • Loading branch information
jurabek authored Jul 14, 2024
1 parent 2e07d78 commit 200c5d2
Show file tree
Hide file tree
Showing 20 changed files with 301 additions and 68 deletions.
1 change: 1 addition & 0 deletions src/backend/services/checkout-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ async function main() {

process.on('SIGINT', async () => {
await otel.shutdown();
await checkoutPublisher.shutdown();
logger.info("Gracefully shutting down from SIGINT (Ctrl-C)");
// some other closing procedures go here
process.exit(0);
Expand Down
5 changes: 5 additions & 0 deletions src/backend/services/checkout-api/src/messagging/publisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class Publisher {

public async start(): Promise<void> {
try {

await this.producer.connect()
} catch (error) {
logger.error('Error connecting the producer: ', error)
Expand All @@ -32,6 +33,10 @@ export class Publisher {
const kafka = new Kafka({
clientId: this.clientId,
brokers: this.brokers,
retry: {
initialRetryTime: 3000,
retries: 15
},
})
return kafka.producer()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import org.jboss.resteasy.reactive.RestQuery;
import org.jurabek.restaurant.order.api.dtos.OrderDto;
import org.jurabek.restaurant.order.api.dtos.OrdersDto;
import org.jurabek.restaurant.order.api.services.OrdersService;

@Path("api/v1/orders")
Expand All @@ -39,9 +40,10 @@ public OrderDto find(@RestQuery String transactionId) {
return null;
}

@GET
public List<OrderDto> getData() {
return this.ordersService.getAll();
@GET()
public OrdersDto getAll(@RestQuery Integer offset, @RestQuery Integer limit) {
var orders = ordersService.getAll(offset, limit);
return new OrdersDto(orders, ordersService.getCount(), offset, limit);
}

@GET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@
public class OrderDto {
private UUID id;
private Date orderedDate;
private UUID cartId;
private UUID transactionId;
private UUID checkoutId;
private List<OrderItemDto> orderItems;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.jurabek.restaurant.order.api.dtos;

import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;

@Data
@AllArgsConstructor
public class OrdersDto {
private List<OrderDto> orders;
private Long total;
private Integer offset;
private Integer limit;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import io.smallrye.common.annotation.Blocking;

import java.util.concurrent.CompletionStage;
import jakarta.transaction.Transactional;

import org.eclipse.microprofile.faulttolerance.Retry;
import org.eclipse.microprofile.reactive.messaging.Acknowledgment;
import org.eclipse.microprofile.reactive.messaging.Incoming;
import org.eclipse.microprofile.reactive.messaging.Message;
import org.eclipse.microprofile.reactive.messaging.Outgoing;
import org.jboss.logging.Logger;
import org.jurabek.restaurant.order.api.services.CheckoutService;

Expand All @@ -19,25 +15,26 @@ public class UserCheckoutEventHandler {

private static final Logger log = Logger.getLogger(UserCheckoutEventHandler.class);

private final CheckoutService checkout;
private final CheckoutService checkoutService;

@Inject
public UserCheckoutEventHandler(CheckoutService checkout) {
this.checkout = checkout;
public UserCheckoutEventHandler(CheckoutService checkoutService) {
this.checkoutService = checkoutService;
}

@Incoming("checkout")
@Acknowledgment(Acknowledgment.Strategy.MANUAL)
@Retry(delay = 10, maxRetries = 5)
@Blocking
public CompletionStage<Void> Handle(Message<UserCheckoutEvent> message) {
try {
log.info("received user checkout event: " + message);
checkout.Checkout(message.getPayload());
return message.ack();
} catch (Exception e) {
log.error("Error processing user checkout event: " + message, e);
return message.nack(e);
}
@Outgoing("order-completed")
@Retry(maxRetries = 5)
@Transactional
public OrderCompleted Handle(UserCheckoutEvent message) {
log.info("received user checkout event: " + message);
var order = checkoutService.CreateOrderFromCheckout(message);

var orderCompleted = new OrderCompleted(order.getId(), order.getCartId(), order.getBuyerId(),
order.getTransactionId(),
order.getOrderedDate());

log.info("order completed: " + orderCompleted);
return orderCompleted;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public OrderItems mapDtoToOrderItems(CustomerBasketItem source) {
public OrderDto mapOrderToDto(Order order) {
var dto = new OrderDto();
dto.setId(order.getId());
dto.setCartId(order.getCartId());
dto.setTransactionId(order.getTransactionId());
dto.setCheckoutId(order.getCheckoutId());

var orderItems = order.getOrderItems()
.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@
import java.util.UUID;

import jakarta.enterprise.context.ApplicationScoped;

import org.jurabek.restaurant.order.api.models.Order;

import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
import io.quarkus.panache.common.Page;

/**
* OrdersRepository
Expand All @@ -23,7 +20,7 @@ public Order getByTransactionId(UUID transactionId) {
return find("transactionId", transactionId).firstResult();
}

public List<Order> fetchAll() {
return find("#Orders.fetchAll").page(Page.ofSize(30)).nextPage().list();
public List<Order> fetchAll(Integer start, Integer end) {
return this.findAll().range(start, end).list();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,34 @@

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;

import org.eclipse.microprofile.reactive.messaging.Channel;
import org.eclipse.microprofile.reactive.messaging.Emitter;
import org.jurabek.restaurant.order.api.events.OrderCompleted;
import org.jurabek.restaurant.order.api.events.UserCheckoutEvent;
import org.jurabek.restaurant.order.api.mappers.OrdersMapper;
import org.jurabek.restaurant.order.api.models.Order;
import org.jurabek.restaurant.order.api.repositories.OrdersRepository;


@ApplicationScoped
public class CheckoutService {

private final OrdersRepository ordersRepository;
private final OrdersMapper mapper;

@Inject
@Channel("order-completed")
private Emitter<OrderCompleted> orderCompletedEventEmitter;

@Inject
public CheckoutService(OrdersRepository ordersRepository, OrdersMapper mapper) {
this.ordersRepository = ordersRepository;
this.mapper = mapper;
}

@Transactional
public void Checkout(UserCheckoutEvent checkoutInfo) {
public Order CreateOrderFromCheckout(UserCheckoutEvent checkoutInfo) {
var order = mapper.mapDtoToOrder(checkoutInfo.getCustomerBasket());
order.setTransactionId(checkoutInfo.getTransactionId());
order.setBuyerId(UUID.fromString(checkoutInfo.getCheckOutInfo().getUserId()));
order.setCheckoutId(checkoutInfo.getCheckoutId());

for (var orderItems : order.getOrderItems()) {
orderItems.setOrder(order);
}
ordersRepository.persist(order);

var event = new OrderCompleted(order.getId(), order.getCartId(), order.getBuyerId(), order.getTransactionId(),
order.getOrderedDate());

orderCompletedEventEmitter.send(event);
return order;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ public interface OrdersService {

OrderDto getOrderByTransactionId(String transactionId);

List<OrderDto> getAll();
List<OrderDto> getAll(Integer offset, Integer limit);

Long getCount();

OrderDto getById(String orderId);
void Delete(String orderId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public OrdersServicesIml(OrdersRepository ordersRepository, OrdersMapper mapper)
}

@Override
public List<OrderDto> getAll() {
return this.ordersRepository.fetchAll()
public List<OrderDto> getAll(Integer offset, Integer limit) {
return this.ordersRepository.fetchAll(offset, offset + limit)
.stream()
.map(o -> mapper.mapOrderToDto(o))
.collect(Collectors.toList());
Expand Down Expand Up @@ -61,4 +61,9 @@ public OrderDto getOrderByTransactionId(String transactionId) {
}
return mapper.mapOrderToDto(order);
}

@Override
public Long getCount() {
return ordersRepository.count();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ public void getShouldReturnData(){
mockResults.add(new OrderDto());
mockResults.add(new OrderDto());

when(ordersService.getAll()).thenReturn(mockResults);
List<OrderDto> result = ordersController.getData();
Assertions.assertEquals(mockResults, result);
verify(ordersService, times(1)).getAll();
when(ordersService.getAll(0, 10)).thenReturn(mockResults);
var result = ordersController.getAll(0, 10);
Assertions.assertEquals(mockResults, result.getOrders());
verify(ordersService, times(1)).getAll(0, 10);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.jurabek.restaurant.order.api.models.OrderItems;
import org.jurabek.restaurant.order.api.repositories.OrdersRepository;


import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.mockito.InjectMock;
import jakarta.inject.Inject;
Expand All @@ -42,17 +41,17 @@ public void setup() {

// @Test
// public void CreateShouldCreateWhenCustomerBasketDto() {
// var customerBasketDto = new CustomerBasket();
// var order = new Order();
// var orderItems = new ArrayList<OrderItems>();
// orderItems.add(new OrderItems());
// order.setOrderItems(orderItems);
// var customerBasketDto = new CustomerBasket();
// var order = new Order();
// var orderItems = new ArrayList<OrderItems>();
// orderItems.add(new OrderItems());
// order.setOrderItems(orderItems);

// when(mapper.mapDtoToOrder(customerBasketDto)).thenReturn(order);
// when(mapper.mapDtoToOrder(customerBasketDto)).thenReturn(order);

// ordersService.Create(customerBasketDto);
// ordersService.Create(customerBasketDto);

// verify(ordersRepository, times(1)).persist(order);
// verify(ordersRepository, times(1)).persist(order);
// }

@Test
Expand All @@ -62,10 +61,10 @@ public void GetAllShouldReturnAllOrderDtos() {

var dto = new OrderDto();

when(ordersRepository.fetchAll()).thenReturn(orders);
when(ordersRepository.fetchAll(0, 10)).thenReturn(orders);
when(mapper.mapOrderToDto(order)).thenReturn(dto);

List<OrderDto> result = ordersService.getAll();
List<OrderDto> result = ordersService.getAll(0, 10);

Assertions.assertEquals(1, result.size());
Assertions.assertEquals(result.get(0), dto);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function DesktopNav() {
<Home className="h-5 w-5" />
</NavItem>

<NavItem href="#" label="Orders">
<NavItem href="/orders" label="Orders">
<ShoppingCart className="h-5 w-5" />
</NavItem>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Button } from "@/components/ui/button";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { TableCell, TableRow } from "@/components/ui/table";
import { calculateTotalPrice, Order } from "@/lib/types/order";
import { MoreHorizontal } from "lucide-react";

export function OrderRow({ order }: { order: Order }) {
return (
<TableRow>
<TableCell className="font-medium">{order.orderedDate.toString()}</TableCell>
<TableCell className="font-medium">{calculateTotalPrice(order)}</TableCell>
<TableCell className="font-medium">{order.cartId}</TableCell>
<TableCell className="font-medium">{order.checkoutId}</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button aria-haspopup="true" size="icon" variant="ghost">
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">Toggle menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>
<form action={() => {}}>
<button type="submit">Delete</button>
</form>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
);
}
Loading

0 comments on commit 200c5d2

Please sign in to comment.