package com.reliancy.dbo; import java.util.ArrayList; import java.util.List; /** * Ordering specification for multiple fields. * *

This class manages an ordered list of field/direction pairs for sorting. * It supports chaining methods to build complex ordering specifications. * *

Example usage: *

{@code
 * Ordering ordering = new Ordering("name ASC, created DESC", entity)
 *     .orderBy(Field.by("status"))
 *     .orderBy(Field.by("priority"), false);
 * }
*/ public class Ordering { private static class FieldOrder { Field field; boolean ascending; FieldOrder(Field field, boolean ascending) { this.field = field; this.ascending = ascending; } } private ArrayList orders = new ArrayList<>(); /** * Creates an empty Ordering. */ public Ordering() { } /** * Creates an Ordering from a string specification. * * @param str String in format "field1 ASC, field2 DESC, ..." or "field1, field2, ..." * @param entity Entity to resolve field names */ public Ordering(String str, Entity entity) { fromString(str, entity); } /** * Creates an Ordering with a single field. * * @param field Field to order by * @param ascending true for ascending, false for descending */ public Ordering(Field field, boolean ascending) { orderBy(field, ascending); } /** * Parses a string specification and adds to this ordering. * * @param str String in format "field1 ASC, field2 DESC, ..." or "field1, field2, ..." * @param entity Entity to resolve field names * @return this for chaining */ public Ordering fromString(String str, Entity entity) { if (str == null || str.trim().isEmpty()) { return this; } String[] parts = str.split(","); for (String part : parts) { part = part.trim(); if (part.isEmpty()) continue; if (!part.contains(" ")) part = part + " ASC"; String[] fieldParts = part.split("\\s+"); Field field = entity.getField(fieldParts[0]); if (field == null) { throw new IllegalArgumentException("Field " + fieldParts[0] + " not found in entity " + entity.getName()); } boolean ascending = fieldParts.length > 1 && fieldParts[1].equalsIgnoreCase("ASC"); orderBy(field, ascending); } return this; } /** * Clears all ordering specifications. * * @return this for chaining */ public Ordering clear() { orders.clear(); return this; } /** * Adds a field to order by (ascending by default). * * @param field Field to order by * @return this for chaining */ public Ordering orderBy(Field field) { return orderBy(field, true); } /** * Adds a field to order by with specified direction. * * @param field Field to order by * @param ascending true for ascending, false for descending * @return this for chaining */ public Ordering orderBy(Field field, boolean ascending) { if (field != null) { orders.add(new FieldOrder(field, ascending)); } return this; } /** * Gets the number of ordering specifications. * * @return number of fields in this ordering */ public int size() { return orders.size(); } /** * Gets the field at the specified index. * * @param index index of the field * @return Field at the index */ public Field getField(int index) { return orders.get(index).field; } /** * Gets whether the field at the specified index is ascending. * * @param index index of the field * @return true if ascending, false if descending */ public boolean isAscending(int index) { return orders.get(index).ascending; } /** * Gets all fields in this ordering. * * @return list of fields */ public List getFields() { List fields = new ArrayList<>(); for (FieldOrder fo : orders) { fields.add(fo.field); } return fields; } /** * Checks if this ordering is empty. * * @return true if no fields are specified */ public boolean isEmpty() { return orders.isEmpty(); } @Override public String toString() { if (orders.isEmpty()) { return ""; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < orders.size(); i++) { if (i > 0) sb.append(", "); FieldOrder fo = orders.get(i); sb.append(fo.field.getName()).append(fo.ascending ? " ASC" : " DESC"); } return sb.toString(); } // Static factory methods for backward compatibility and convenience /** * Creates an Ordering with a single ascending field. * * @param field Field to order by * @return new Ordering instance */ public static Ordering ascending(Field field) { return new Ordering(field, true); } /** * Creates an Ordering with a single descending field. * * @param field Field to order by * @return new Ordering instance */ public static Ordering descending(Field field) { return new Ordering(field, false); } /** * Creates an Ordering with a single ascending field. * * @param field Field to order by * @return new Ordering instance */ public static Ordering by(Field field) { return new Ordering(field, true); } }