diff options
Diffstat (limited to 'Services/FeedService.cs')
| -rw-r--r-- | Services/FeedService.cs | 212 |
1 files changed, 0 insertions, 212 deletions
diff --git a/Services/FeedService.cs b/Services/FeedService.cs deleted file mode 100644 index 3744e73..0000000 --- a/Services/FeedService.cs +++ /dev/null @@ -1,212 +0,0 @@ -using HyperBooru.ApiModels; -using Microsoft.EntityFrameworkCore; - -namespace HyperBooru.Services; - -public interface IFeedService { - public Media[] LoadChunk( - bool selectIngest, - bool includeNsfw, - Media? key = null, - int count = 50, - SortOrder sortOrder = SortOrder.ObjectId); - - public Media[] LoadChunk( - bool selectIngest, - bool includeNsfw, - string query, - Media? key = null, - int count = 50, - SortOrder sortOrder = SortOrder.ObjectId); - - public Media[] LoadChunk( - bool selectIngest, - bool includeNsfw, - Guid tagId, - Media? key = null, - int count = 50, - SortOrder sortOrder = SortOrder.ObjectId); - - public Media[] LoadChunk(FeedRequest feedRequest); -} - -public class FeedService : IFeedService { - private IDbContextFactory<HBContext> dbFactory; - - public FeedService(IDbContextFactory<HBContext> dbFactory) => - this.dbFactory = dbFactory; - - public Media[] LoadChunk( - bool selectIngest, - bool includeNsfw, - Media? continuationToken, - int count, - SortOrder sortOrder) => LoadChunkInternal( - selectIngest, includeNsfw, null, null, continuationToken?.Guid, count, sortOrder); - - public Media[] LoadChunk( - bool selectIngest, - bool includeNsfw, - string query, - Media? continuationToken, - int count, - SortOrder sortOrder) => LoadChunkInternal( - selectIngest, includeNsfw, query, null, continuationToken?.Guid, count, sortOrder); - - public Media[] LoadChunk( - bool selectIngest, - bool includeNsfw, - Guid tagId, - Media? continuationToken, - int count, - SortOrder sortOrder) => LoadChunkInternal( - selectIngest, includeNsfw, null, tagId, continuationToken?.Guid, count, sortOrder); - - public Media[] LoadChunk(FeedRequest feedRequest) { - switch(feedRequest) { - case FeedSearchRequest searchRequest: - return LoadChunkInternal( - selectIngest: searchRequest.SelectIngest, - includeNsfw: searchRequest.IncludeNsfw, - query: searchRequest.Query, - tagId: null, - continuationToken: searchRequest.ContinuationToken, - count: searchRequest.Count, - sortOrder: searchRequest.SortOrder); - case FeedTagRequest tagRequest: - return LoadChunkInternal( - selectIngest: tagRequest.SelectIngest, - includeNsfw: tagRequest.IncludeNsfw, - query: null, - tagId: tagRequest.TagId, - continuationToken: tagRequest.ContinuationToken, - count: tagRequest.Count, - sortOrder: tagRequest.SortOrder); - default: - return LoadChunkInternal( - selectIngest: feedRequest.SelectIngest, - includeNsfw: feedRequest.IncludeNsfw, - query: null, - tagId: null, - continuationToken: feedRequest.ContinuationToken, - count: feedRequest.Count, - sortOrder: feedRequest.SortOrder); - } - } - - private Media[] LoadChunkInternal( - bool selectIngest, - bool includeNsfw, - string? query, - Guid? tagId, - Guid? continuationToken, - int count, - SortOrder sortOrder) { - - if(selectIngest && !includeNsfw) - return Array.Empty<Media>(); - - using var db = dbFactory.CreateDbContext(); - - IQueryable<Media> media = db.Media - .AsSingleQuery() - .AsNoTracking() - .Include(m => m.Tags) - .Include(m => m.CurrentUploadedFile); - - if(!includeNsfw) - media = media - .Where(m => !TagsThatImply(db, HBContext.NsfwTag) - .Intersect(m.Tags.Select(t => t.TagDefinitionId)) - .Any()); - - if(selectIngest) { - media = media - .Where(m => m.Tags - .Select(t => t.TagDefinitionId) - .Contains((int) HBObjectId.IngestTag)); - } else { - media = media - .Where(m => !m.Tags - .Select(t => t.TagDefinitionId) - .Contains((int) HBObjectId.IngestTag)); - } - - if(query is not null) { - media = Search(media, query); - } else if(tagId is not null) { - media = media - .Where(m => TagsThatImply(db, (Guid) tagId) - .Intersect(m.Tags.Select(t => t.TagDefinitionId)) - .Any()); - } - - if(continuationToken is not null) - media = media - .Where(m => m.ObjectId > db.Media.First(m => m.Guid == continuationToken).ObjectId); - - switch(sortOrder) { - case SortOrder.ObjectId: - media = media.OrderBy(m => m.ObjectId); - break; - case SortOrder.LastWriteTime: - media = media.OrderBy(m => m.CurrentUploadedFile!.LastWriteTime); - break; - case SortOrder.Random: - media = media.OrderBy(m => EF.Functions.Random()); - break; - } - - return media - .Take(count) - .ToArray(); - } - - private static IQueryable<Media> Search(IQueryable<Media> media, string query) { - // TODO: search implicit tags as well - - query = query.ToLower().Trim(); - - return media - .Where(m => - (m.ShortDescription != null && m.ShortDescription.ToLower().Contains(query)) || - (m.LongDescription != null && m.LongDescription.ToLower().Contains(query)) || - (m.UploadedFiles.Any(uf => uf.Filename != null && uf.Filename.ToLower().Contains(query))) || - (m.OcrData != null && m.OcrData.SearchableText.ToLower().Contains(query)) || - (m.Tags.Any(t => t.TagDefinition.Name.ToLower().Contains(query)))); - } - - private static IQueryable<int> TagsThatImply(HBContext db, Guid tagId) => - db.Database.SqlQueryRaw<int>(""" - WITH RECURSIVE basetag AS ( - SELECT "ObjectId" FROM "Objects" WHERE "Guid" = {0} - ), - impliedtags AS ( - SELECT - "TagDefinitionObjectId" - FROM - "TagDefinitionTagDefinition" - INNER JOIN - basetag - ON - "ImplicitTagsObjectId" = basetag."ObjectId" - UNION - SELECT - "TagDefinitionTagDefinition"."TagDefinitionObjectId" - FROM - "TagDefinitionTagDefinition" - INNER JOIN - impliedtags - ON - impliedtags."TagDefinitionObjectId" = "TagDefinitionTagDefinition"."ImplicitTagsObjectId" - ) - SELECT DISTINCT - "TagDefinitionObjectId" AS "Value" - FROM impliedtags - UNION - SELECT - "ObjectId" AS "Value" - FROM - basetag - """, tagId); -} |
