using Nuuru.Server.Models.Booru; namespace Nuuru.Server.Services.Search.Nodes; /// /// Base class for all search AST nodes. /// public abstract class SearchNode; #region Tag Nodes /// /// A filter for a specific tag. /// public class TagNode : SearchNode { public string Name { get; } public bool Negated { get; } public TagNode(string name, bool negated = false) { Name = name.ToLowerInvariant(); Negated = negated; } } /// /// A wildcard filter for tags matching a prefix. /// public class WildcardTagNode : SearchNode { public string Prefix { get; } public bool Negated { get; } public WildcardTagNode(string prefix, bool negated = false) { Prefix = prefix.ToLowerInvariant(); Negated = negated; } } /// /// A filter for a tag with a specific category (e.g., character:naruto). /// public class CategoryTagNode : SearchNode { public string CategorySlug { get; } public string Name { get; } public bool Negated { get; } public CategoryTagNode(string categorySlug, string name, bool negated = false) { CategorySlug = categorySlug.ToLowerInvariant(); Name = name.ToLowerInvariant(); Negated = negated; } } #endregion #region Boolean Nodes /// /// Combines multiple nodes with AND logic (all must match). /// public class AndNode : SearchNode { public List Children { get; } public AndNode(List children) { Children = children; } } /// /// Combines multiple nodes with OR logic (at least one must match). /// public class OrNode : SearchNode { public List Children { get; } public OrNode(List children) { Children = children; } } #endregion #region Meta Filter Nodes /// /// Base class for meta-tag filter nodes. /// public abstract class MetaFilterNode : SearchNode { public bool Negated { get; init; } } /// /// Filter by content rating. /// public class RatingFilterNode : MetaFilterNode { public PostRating Rating { get; } public RatingFilterNode(PostRating rating) { Rating = rating; } } /// /// Filter by content category. /// public class CategoryFilterNode : MetaFilterNode { public PostCategory Category { get; } public CategoryFilterNode(PostCategory category) { Category = category; } } /// /// Filter by uploader username. /// public class UploaderFilterNode : MetaFilterNode { public string Username { get; } public UploaderFilterNode(string username) { Username = username.ToLowerInvariant(); } } /// /// Filter by numeric range (id, width, height, filesize, tagcount). /// public class NumericRangeFilterNode : MetaFilterNode { public string Field { get; } public long? Min { get; } public long? Max { get; } public NumericRangeFilterNode(string field, long? min = null, long? max = null) { Field = field.ToLowerInvariant(); Min = min; Max = max; } } /// /// Filter by date range. /// public class DateRangeFilterNode : MetaFilterNode { public DateTime? Min { get; } public DateTime? Max { get; } public DateRangeFilterNode(DateTime? min = null, DateTime? max = null) { Min = min; Max = max; } } /// /// Filter by file type (MIME type). /// public class FileTypeFilterNode : MetaFilterNode { public string MimeType { get; } public FileTypeFilterNode(string mimeType) { MimeType = mimeType.ToLowerInvariant(); } } /// /// Filter by boolean status (approved, pending, featured, etc.). /// public class StatusFilterNode : MetaFilterNode { public string Status { get; } public StatusFilterNode(string status) { Status = status.ToLowerInvariant(); } } #endregion #region Ordering Node /// /// Specifies sort order for results. /// public class OrderByNode : SearchNode { public string Field { get; } public bool Descending { get; } public OrderByNode(string field, bool descending = true) { Field = field.ToLowerInvariant(); Descending = descending; } } #endregion