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