OrderGraphQlController.java

package io.slayyyyer.orders.graphql;

import io.slayyyyer.orders.domain.Order;
import io.slayyyyer.orders.domain.OrderStatus;
import io.slayyyyer.orders.domain.Product;
import io.slayyyyer.orders.repository.OrderPage;
import io.slayyyyer.orders.service.CreatedOrder;
import io.slayyyyer.orders.service.CustomerService;
import io.slayyyyer.orders.service.OrderService;
import io.slayyyyer.orders.service.ProductService;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.MutationMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;

@Controller
public class OrderGraphQlController {

    private final OrderService orders;
    private final CustomerService customers;
    private final ProductService products;

    public OrderGraphQlController(OrderService orders, CustomerService customers, ProductService products) {
        this.orders = orders;
        this.customers = customers;
        this.products = products;
    }

    @QueryMapping
    public Object customer(@Argument String id) {
        return customers.require(UUID.fromString(id));
    }

    @QueryMapping
    public Order order(@Argument String id) {
        return orders.require(UUID.fromString(id));
    }

    @QueryMapping
    public List<Product> products(@Argument String query, @Argument Integer limit) {
        int effectiveLimit = limit == null ? 20 : Math.min(limit, 100);
        if (effectiveLimit < 1) {
            throw new IllegalArgumentException("limit must be between 1 and 100");
        }
        return products.search(query, effectiveLimit, 0);
    }

    @QueryMapping
    public OrderConnection orders(
            @Argument String customerId,
            @Argument String status,
            @Argument Integer page,
            @Argument Integer size) {

        int effectivePage = page == null ? 0 : page;
        int effectiveSize = size == null ? 20 : size;

        OrderPage result = orders.byCustomer(
                UUID.fromString(customerId), parseStatus(status), effectivePage, effectiveSize);

        return new OrderConnection(
                result.orders(), result.page(), result.size(), result.totalCount(), result.hasNextPage());
    }

    @MutationMapping
    public CreatedOrder createOrder(@Argument CreateOrderInput input) {
        return orders.create(input.toCommand());
    }

    @MutationMapping
    public Order changeOrderStatus(@Argument String id, @Argument OrderStatus status) {
        return orders.transition(UUID.fromString(id), status);
    }

    private static OrderStatus parseStatus(String status) {
        if (status == null || status.isBlank()) {
            return null;
        }
        try {
            return OrderStatus.valueOf(status.trim().toUpperCase(Locale.ROOT));
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("unknown order status: " + status);
        }
    }

    public record OrderConnection(
            List<Order> items, int page, int size, long totalCount, boolean hasNextPage) {
    }
}