using OpenNest; namespace OpenNest.Data; /// /// One bounded page request for browsing the drawing library /// (GET /api/drawings/query). The server filters and pages in SQL; the /// client and server share these bounds. /// public sealed class DrawingLibraryQuery { public const int DefaultLimit = 100; public const int MaxLimit = 500; public const int MaxSearchLength = 200; /// /// Case-insensitive (ASCII) substring of name, customer or notes. Blank means no filter. /// public string Search { get; init; } = ""; /// Exact customer, compared by . Blank means any. public string Customer { get; init; } = ""; /// Exact material name, compared by . Blank means any. public string MaterialName { get; init; } = ""; /// Exact grade, compared by . Blank means any. public string MaterialGrade { get; init; } = ""; /// Exact thickness after rounding to four decimals; null means any. public double? Thickness { get; init; } public CutType? CutType { get; init; } public bool IncludeArchived { get; init; } /// Column to order by; ties are broken by id in the same direction. public DrawingSortField Sort { get; init; } = DrawingSortField.SavedAt; /// Largest/newest/Z first when true (the default, newest saved first). public bool Descending { get; init; } = true; public int Offset { get; init; } public int Limit { get; init; } = DefaultLimit; /// The search text as matched: trimmed, never null. public string NormalizedSearch => (Search ?? "").Trim(); /// The first violated bound, or null when the query may be sent. public string? GetValidationError() { if (!Enum.IsDefined(Sort)) return "sort must be a supported column."; if (CutType is { } cutType && !Enum.IsDefined(cutType)) return "cutType must be Laser, Waterjet or Plasma."; if (Thickness is { } thickness && (!double.IsFinite(thickness) || thickness < 0)) return "thickness must be a finite number, zero or greater."; if (Offset < 0) return "offset must be zero or greater."; if (Limit < 1 || Limit > MaxLimit) return $"limit must be between 1 and {MaxLimit}."; return DrawingLibraryRules.TextError("search", NormalizedSearch, MaxSearchLength) ?? DrawingLibraryRules.TextError("customer", Customer ?? "", DrawingLibraryRules.MaxTextLength) ?? DrawingLibraryRules.TextError("materialName", MaterialName ?? "", DrawingLibraryRules.MaxTextLength) ?? DrawingLibraryRules.TextError("materialGrade", MaterialGrade ?? "", DrawingLibraryRules.MaxTextLength); } }