SearchProvider.cs

194 lines | 6.177 kB Blame History Raw Download
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;

using Microsoft.EntityFrameworkCore;

using Tools.PdfProvider;

using Calibre.Model.Database;
using Calibre.Model.Database.Entities;

using Calibre.Model.Domain.Entities;

using LibraryText.Entities;

namespace Calibre.Model.Domain.Dal
{
    public class SearchProvider
    {
        private readonly SimplePdfReader SimplePdfReader;


        public SearchProvider(
            SimplePdfReader simplePdfReader
            )
        {
            SimplePdfReader = simplePdfReader;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="whereExpression">Фильтр When</param>
        /// <param name="includeTags">Подгружать теги</param>
        /// <param name="includeAutors">Подгружать авторов</param>
        /// <param name="includeFileData">Подгрудать данные файлов книги</param>
        /// <param name="includeLang">Подгружать данные языков</param>
        /// <param name="includeCover">Подгружать обложку</param>
        /// <param name="libraries"></param>
        public async Task<Dictionary<Library, BookWithLibraryContainer[]>> GetBooksByLibrariesAsync(            
            Func<Book, bool> whereExpression = null,
            bool includeTags = true,
            bool includeAutors = true,
            bool includeFileData = true,
            bool includeLang = true,
            bool includeCover = true,
            params Library[] libraries
            )
        {
            List<CalibreContext> contexts
                = new List<CalibreContext>(libraries.Length);

            Dictionary<Library, Task<Book[]>> data
                = new Dictionary<Library, Task<Book[]>>(libraries.Length);

            try
            {
                foreach (var elem in libraries)
                {
                    var connectionString = elem.BuildConnectionString();

                    var context = new CalibreContext(connectionString)
                    {
                        AsNoTracking = true,
                        //LibraryDirectory = libraryDirectory
                    };
                    contexts.Add(context);

                    IQueryable<Book> selectExpr = context
                        .Books;

                    //1) Подгружаем теги
                    if (includeTags)
                    {
                        selectExpr = selectExpr
                            .Include(e => e.Tags)
                            .ThenInclude(e => e.TagItem);
                    }

                    //2) Подгружаем авторов
                    if (includeAutors)
                    {
                        selectExpr = selectExpr
                            .Include(e => e.Autors)
                            .ThenInclude(e => e.AuthorItem);
                    }

                    //3) Подгружаем данные о фалах
                    if (includeFileData)
                    {
                        selectExpr = selectExpr
                            .Include(e => e.FileData);
                    }

                    if (includeLang)
                    {
                        selectExpr = selectExpr
                            .Include(e => e.Languages)
                            .ThenInclude(e => e.LangItem);
                    }

                    //4) Условие поиска
                    if (whereExpression != null)
                    {
                        selectExpr = selectExpr
                            .Where(whereExpression)
                            .AsQueryable();
                    }

                    var selectResultTask = selectExpr.ToArrayAsync();
                    data.Add(elem, selectResultTask);
                }

                await Task.WhenAll(
                    data.Values.ToArray()
                    );
            }
            finally
            {
                contexts.ForEach(
                    e => e.Dispose()
                    );
            }


            Dictionary<Library, BookWithLibraryContainer[]> result 
                = new Dictionary<Library, BookWithLibraryContainer[]>(libraries.Length);
            foreach (var elem in data)
            {
                var library = elem.Key;
                var libraryProxy = new ImmutableProxy<Library>(library);

                var libBooks = elem.Value.Result;

                var loadBooksTasks = libBooks
                    .Select(
                        e2 => BookWithLibraryContainer.CreateAsync(
                            book: e2,
                            library: libraryProxy, 
                            loadCover: includeCover
                            )
                        )
                    .ToArray();
                await Task.WhenAll(loadBooksTasks);

                var books = loadBooksTasks
                    .Select(e => e.Result)
                    .ToArray();

                result.Add(library, books);
            }

            return result;
        }

        public async Task<Dictionary<BookWithLibraryContainer, string>> GetTextByBooksAsync(
            IList<BookWithLibraryContainer> books,
            bool ignoreError,
            Func<BookWithLibraryContainer, string, bool> whereExpression = null
            )
        {
            Dictionary<BookWithLibraryContainer, string> result 
                = new Dictionary<BookWithLibraryContainer, string>(books.Count);

            foreach (var elem in books)
            {
                var bookText = await elem.ReadFileAsync(
                    async (s) => 
                    {
                        var res = await SimplePdfReader.ReadPdfAsync(s, ignoreError);
                        return res;
                    }
                    );

                if (whereExpression != null)
                {
                    if (!whereExpression(elem, bookText)) 
                    {
                        continue;
                    }
                }

                result.Add(elem, bookText);
            }

            return result;
        }
    }
}