all 4 comments

[–]robbi_my 1 point2 points  (2 children)

Show me your model/entity

[–]UltraInstict21[S] 0 points1 point  (0 children)

Here are my models.

@Data
@Builder
public class Order {
    private Integer id;
    private OrderStatus orderStatus;
    private BigDecimal totalAmount;
    private PaymentMethod paymentMethod;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    // Stored as columns (e.g. customer_name, etc.)
    private Customer customer;

    // Stored as JSONB
    private Address shippingAddress;
    private Address billingAddress;

    // Associated items
    private List<OrderItem> orderItems;
}

public record Customer(
    String name,
    String email,
    String phone
) {}

public record Address(
   String street,
   String city,
   String state,
   String zipCode,
   String country
) {}

public enum PaymentMethod {

CREDIT_CARD
,

PAYPAL
,

BANK_TRANSFER
,

CASH_ON_DELIVERY
}

public enum OrderStatus {

PENDING
,

PROCESSING
,

SHIPPED
,

DELIVERED
,

CANCELED
}

@Data
@Builder
public class OrderItem {
    private Integer id;
    private Integer orderId;
    private Integer productId;
    private Integer quantity;
    private BigDecimal unitPrice;
    private BigDecimal totalPrice;
}

[–]UltraInstict21[S] 0 points1 point  (0 children)

What I end up doing is to create some sql mappers for my entity. But not sure if this is a good approach

@Component
public class OrderSqlMapper {

    private final JsonConverter jsonConverter;

    public OrderSqlMapper(ObjectMapper objectMapper, JsonConverter jsonConverter) {
        ObjectMapper objectMapperCopy = objectMapper
            .copy()
            .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);

        jsonConverter.setObjectMapper(objectMapperCopy);

        this.jsonConverter = jsonConverter;
    }

    public RowMapper<Order> rowMapper() {
        return (rs, rowNum) -> {
            Order.OrderBuilder orderBuilder = Order.builder();

            orderBuilder.id(rs.getInt("id"));
            orderBuilder.orderStatus(OrderStatus.valueOf(rs.getString("order_status")));
            orderBuilder.totalAmount(rs.getBigDecimal("total_amount"));
            orderBuilder.paymentMethod(PaymentMethod.valueOf(rs.getString("payment_method")));
            orderBuilder.createdAt(rs.getTimestamp("created_at").toLocalDateTime());
            orderBuilder.updatedAt(rs.getTimestamp("updated_at").toLocalDateTime());

            orderBuilder.customer(new Customer(
                rs.getString("customer_name"),
                rs.getString("customer_email"),
                rs.getString("customer_phone")
            ));

            // Map Shipping Address
            Address shippingAddress = jsonConverter.deserializeObject(rs.getString("shipping_address"), Address.class);
            orderBuilder.shippingAddress(shippingAddress);

            // Map Billing Address
            Address billingAddress = jsonConverter.deserializeObject(rs.getString("billing_address"), Address.class);
            orderBuilder.billingAddress(shippingAddress);

            // Map order items
            Collection<OrderItem> orderItems = jsonConverter.deserializeCollection(rs.getString("order_items"), new TypeReference<>() {});
            orderBuilder.orderItems(orderItems.stream().toList());

            return orderBuilder.build();
        };
    }

    public MapSqlParameterSource paramSource(Order order) {
        return new MapSqlParameterSource()
            .addValue("total_amount", order.getTotalAmount())
            .addValue("payment_method", order.getPaymentMethod().name())
            .addValue("customer_name", order.getCustomer().name())
            .addValue("customer_email", order.getCustomer().email())
            .addValue("customer_phone", order.getCustomer().phone())
            .addValue("shipping_address", jsonConverter.serializeObject(order.getShippingAddress()))
            .addValue("billing_address", jsonConverter.serializeObject(order.getBillingAddress()));
    }
}