using DuoVia.FuzzyStrings; using NTDLS.SqliteDapperWrapper; using ZelWiki.Caching; using ZelWiki.Engine.Library; using ZelWiki.Library; using ZelWiki.Models.DataModels; namespace ZelWiki.Repository { public static class PageRepository { public static Page? GetPageRevisionInfoById(int pageId, int? revision = null) { var param = new { PageId = pageId, Revision = revision }; return ManagedDataStorage.Pages.QuerySingleOrDefault("GetPageRevisionInfoById.sql", param); } public static ProcessingInstructionCollection GetPageProcessingInstructionsByPageId(int pageId, bool allowCache = true) { if (allowCache) { var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Page, [pageId]); if (!WikiCache.TryGet(cacheKey, out var result)) { result = GetPageProcessingInstructionsByPageId(pageId, false); WikiCache.Put(cacheKey, result); } return result; } var param = new { PageId = pageId }; return new ProcessingInstructionCollection() { Collection = ManagedDataStorage.Pages .Query("GetPageProcessingInstructionsByPageId.sql", param).ToList() }; } public static List GetPageTagsById(int pageId, bool allowCache = true) { if (allowCache) { var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Page, [pageId]); if (!WikiCache.TryGet>(cacheKey, out var result)) { result = GetPageTagsById(pageId, false); WikiCache.Put(cacheKey, result); } return result; } var param = new { PageId = pageId }; return ManagedDataStorage.Pages.Query("GetPageTagsById.sql", param).ToList(); } public static List GetPageRevisionsInfoByNavigationPaged( string navigation, int pageNumber, string? orderBy = null, string? orderByDirection = null, int? pageSize = null) { pageSize ??= ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { Navigation = navigation, PageNumber = pageNumber, PageSize = pageSize }; return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); var query = RepositoryHelper.TransposeOrderby("GetPageRevisionsInfoByNavigationPaged.sql", orderBy, orderByDirection); return o.Query(query, param).ToList(); }); } public static List GetTopRecentlyModifiedPagesInfoByUserId(Guid userId, int topCount) { var param = new { UserId = userId, TopCount = topCount }; return ManagedDataStorage.Pages.Query("GetTopRecentlyModifiedPagesInfoByUserId.sql", param) .ToList(); } public static string? GetPageNavigationByPageId(int pageId) { var param = new { PageId = pageId }; return ManagedDataStorage.Pages.ExecuteScalar("GetPageNavigationByPageId.sql", param); } public static List GetTopRecentlyModifiedPagesInfo(int topCount) { var param = new { TopCount = topCount }; return ManagedDataStorage.Pages.Query("GetTopRecentlyModifiedPagesInfo.sql", param).ToList(); } private static List GetFuzzyPageSearchTokens(List tokens, double minimumMatchScore) { return ManagedDataStorage.Pages.Ephemeral(o => { var param = new { MinimumMatchScore = minimumMatchScore, TokenCount = tokens.Count }; using var tempTable = o.CreateTempTableFrom("TempSearchTerms", tokens.Distinct()); return o.Query("GetFuzzyPageSearchTokens.sql", param).ToList(); }); } private static List GetExactPageSearchTokens(List tokens, double minimumMatchScore) { return ManagedDataStorage.Pages.Ephemeral(o => { var param = new { MinimumMatchScore = minimumMatchScore, TokenCount = tokens.Count }; using var tempTable = o.CreateTempTableFrom("TempSearchTerms", tokens.Distinct()); return o.Query("GetExactPageSearchTokens.sql", param).ToList(); }); } private static List GetMeteredPageSearchTokens(List searchTerms, bool allowFuzzyMatching, bool allowCache = true) { if (allowCache) { var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Search, [string.Join(',', searchTerms), allowFuzzyMatching]); if (!WikiCache.TryGet>(cacheKey, out var result)) { result = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching, false); WikiCache.Put(cacheKey, result); } return result; } var minimumMatchScore = ConfigurationRepository.Get("Search", "Minimum Match Score"); var searchTokens = (from o in searchTerms select new PageToken { Token = o, DoubleMetaphone = o.ToDoubleMetaphone() }).ToList(); if (allowFuzzyMatching == true) { var allTokens = GetExactPageSearchTokens(searchTokens, minimumMatchScore / 2.0); var fuzzyTokens = GetFuzzyPageSearchTokens(searchTokens, minimumMatchScore / 2.0); allTokens.AddRange(fuzzyTokens); return allTokens .GroupBy(token => token.PageId) .Where(group => group.Sum(g => g.Score) >= minimumMatchScore) .Select(group => new PageSearchToken { PageId = group.Key, Match = group.Max(g => g.Match), Weight = group.Max(g => g.Weight), Score = group.Max(g => g.Score) }).ToList(); } else { return GetExactPageSearchTokens(searchTokens, minimumMatchScore / 2.0); } } public static List PageSearch(List searchTerms) { if (searchTerms.Count == 0) { return new List(); } var allowFuzzyMatching = ConfigurationRepository.Get("Search", "Allow Fuzzy Matching"); var meteredSearchTokens = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching == true); if (meteredSearchTokens.Count == 0) { return new List(); } return ManagedDataStorage.Pages.Ephemeral(o => { var param = new { MaximumScore = meteredSearchTokens.Max(t => t.Score) }; using var users_db = o.Attach("users.db", "users_db"); using var tempTable = o.CreateTempTableFrom("TempSearchTerms", meteredSearchTokens); return o.Query("PageSearch.sql", param).ToList(); }); } public static List PageSearchPaged(List searchTerms, int pageNumber, int? pageSize = null, bool? allowFuzzyMatching = null) { if (searchTerms.Count == 0) { return new List(); } pageSize ??= ConfigurationRepository.Get("Customization", "Pagination Size"); allowFuzzyMatching ??= ConfigurationRepository.Get("Search", "Allow Fuzzy Matching"); var meteredSearchTokens = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching == true); if (meteredSearchTokens.Count == 0) { return new List(); } return ManagedDataStorage.Pages.Ephemeral(o => { var param = new { PageNumber = pageNumber, PageSize = pageSize, MaximumScore = meteredSearchTokens.Max(t => t.Score) }; using var users_db = o.Attach("users.db", "users_db"); using var tempTable = o.CreateTempTableFrom("TempSearchTerms", meteredSearchTokens); var results = o.Query("PageSearchPaged.sql", param).ToList(); return results; }); } public static List GetSimilarPagesPaged(int pageId, int similarity, int pageNumber, int? pageSize = null) { pageSize ??= ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageId = pageId, Similarity = similarity, PageNumber = pageNumber, PageSize = pageSize }; return ManagedDataStorage.Pages.Query("GetSimilarPagesPaged.sql", param).ToList(); } public static List GetRelatedPagesPaged(int pageId, int pageNumber, int? pageSize = null) { pageSize ??= ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageId = pageId, PageNumber = pageNumber, PageSize = pageSize }; return ManagedDataStorage.Pages.Query("GetRelatedPagesPaged.sql", param).ToList(); } public static void FlushPageCache(int pageId) { var pageNavigation = GetPageNavigationByPageId(pageId); WikiCache.ClearCategory(WikiCacheKey.Build(WikiCache.Category.Page, [pageNavigation])); WikiCache.ClearCategory(WikiCacheKey.Build(WikiCache.Category.Page, [pageId])); } public static void InsertPageComment(int pageId, Guid userId, string body) { var param = new { PageId = pageId, UserId = userId, Body = body, CreatedDate = DateTime.UtcNow }; ManagedDataStorage.Pages.Execute("InsertPageComment.sql", param); FlushPageCache(pageId); } public static void DeletePageCommentById(int pageId, int commentId) { var param = new { PageId = pageId, CommentId = commentId }; ManagedDataStorage.Pages.Execute("DeletePageCommentById.sql", param); FlushPageCache(pageId); } public static void DeletePageCommentByUserAndId(int pageId, Guid userId, int commentId) { var param = new { PageId = pageId, UserId = userId, CommentId = commentId }; ManagedDataStorage.Pages.Execute("DeletePageCommentByUserAndId.sql", param); FlushPageCache(pageId); } public static List GetPageCommentsPaged(string navigation, int pageNumber, bool allowCache = true) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); if (allowCache) { var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Page, [navigation, pageNumber, pageSize]); if (!WikiCache.TryGet>(cacheKey, out var result)) { result = GetPageCommentsPaged(navigation, pageNumber, false); WikiCache.Put(cacheKey, result); } return result; } var param = new { Navigation = navigation, PageNumber = pageNumber, PageSize = pageSize }; return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); return o.Query("GetPageCommentsPaged.sql", param).ToList(); }); } public static List GetMissingPagesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageNumber = pageNumber, PageSize = pageSize }; var query = RepositoryHelper.TransposeOrderby("GetMissingPagesPaged.sql", orderBy, orderByDirection); return ManagedDataStorage.Pages.Query(query, param).ToList(); } public static void UpdateSinglePageReference(string pageNavigation, int pageId) { var param = new { @PageId = pageId, @PageNavigation = pageNavigation }; ManagedDataStorage.Pages.Execute("UpdateSinglePageReference.sql", param); FlushPageCache(pageId); } public static void UpdatePageReferences(int pageId, List referencesPageNavigations) { ManagedDataStorage.Pages.Ephemeral(o => { var param = new { PageId = pageId }; using var tempTable = o.CreateTempTableFrom("TempReferences", referencesPageNavigations.Distinct()); return o.Query("UpdatePageReferences.sql", param).ToList(); }); FlushPageCache(pageId); } public static List GetAllPagesByInstructionPaged(int pageNumber, string? instruction = null) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageNumber = pageNumber, PageSize = pageSize, Instruction = instruction }; return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); return o.Query("GetAllPagesByInstructionPaged.sql", param).ToList(); }); } public static List GetDeletedPageIdsByTokens(List? tokens) { if (tokens == null || tokens.Count == 0) { return new List(); } return ManagedDataStorage.DeletedPages.Ephemeral(o => { var param = new { TokenCount = tokens.Count }; using var tempTable = o.CreateTempTableFrom("TempTokens", tokens); return o.Query("GetDeletedPageIdsByTokens.sql", param).ToList(); }); } public static List GetPageIdsByTokens(List? tokens) { if (tokens == null || tokens.Count == 0) { return new List(); } return ManagedDataStorage.Pages.Ephemeral(o => { var param = new { TokenCount = tokens.Count }; using var tempTable = o.CreateTempTableFrom("TempTokens", tokens); return o.Query("GetPageIdsByTokens.sql", param).ToList(); }); } public static List GetAllNamespacePagesPaged(int pageNumber, string namespaceName, string? orderBy = null, string? orderByDirection = null) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageNumber = pageNumber, PageSize = pageSize, Namespace = namespaceName }; return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); var query = RepositoryHelper.TransposeOrderby("GetAllNamespacePagesPaged.sql", orderBy, orderByDirection); return o.Query(query, param).ToList(); }); } /// /// /// /// /// /// /// /// public static List GetAllPagesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null, List? searchTerms = null) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageNumber = pageNumber, PageSize = pageSize }; if (searchTerms?.Count > 0) { var pageIds = GetPageIdsByTokens(searchTerms); return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); using var deletedpagerevisions_db = o.Attach("deletedpagerevisions.db", "deletedpagerevisions_db"); using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds); var query = RepositoryHelper.TransposeOrderby("GetAllPagesByPageIdPaged.sql", orderBy, orderByDirection); return o.Query(query, param).ToList(); }); } return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); using var deletedpagerevisions_db = o.Attach("deletedpagerevisions.db", "deletedpagerevisions_db"); var query = RepositoryHelper.TransposeOrderby("GetAllPagesPaged.sql", orderBy, orderByDirection); return o.Query(query, param).ToList(); }); } /// /// /// /// /// /// /// /// public static List GetAllDeletedPagesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null, List? searchTerms = null) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageNumber = pageNumber, PageSize = pageSize }; if (searchTerms?.Count > 0) { var pageIds = GetDeletedPageIdsByTokens(searchTerms); return ManagedDataStorage.DeletedPages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds); var query = RepositoryHelper.TransposeOrderby("GetAllDeletedPagesByPageIdPaged.sql", orderBy, orderByDirection); return o.Query(query, param).ToList(); }); } return ManagedDataStorage.DeletedPages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); var query = RepositoryHelper.TransposeOrderby("GetAllDeletedPagesPaged.sql", orderBy, orderByDirection); return o.Query(query, param).ToList(); }); } public static List GetAllNamespacesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageNumber = pageNumber, PageSize = pageSize }; var query = RepositoryHelper.TransposeOrderby("GetAllNamespacesPaged.sql", orderBy, orderByDirection); return ManagedDataStorage.Pages.Query(query, param).ToList(); } public static List GetAllNamespaces() => ManagedDataStorage.Pages.Query("GetAllNamespaces.sql").ToList(); public static List GetAllPages() => ManagedDataStorage.Pages.Query("GetAllPages.sql").ToList(); public static void UpdatePageProcessingInstructions(int pageId, List instructions) { ManagedDataStorage.Pages.Ephemeral(o => { var param = new { PageId = pageId }; instructions = instructions.Select(o => o.ToLower()).Distinct().ToList(); using var tempTable = o.CreateTempTableFrom("TempInstructions", instructions); return o.Query("UpdatePageProcessingInstructions.sql", param).ToList(); }); FlushPageCache(pageId); } public static Page? GetPageRevisionById(int pageId, int? revision = null) { var param = new { PageId = pageId, Revision = revision }; return ManagedDataStorage.Pages.QuerySingleOrDefault("GetPageRevisionById.sql", param); } public static void SavePageSearchTokens(List items) { ManagedDataStorage.Pages.Ephemeral(o => { using var tempTable = o.CreateTempTableFrom("TempTokens", items.Distinct()); return o.Query("SavePageSearchTokens.sql").ToList(); }); } public static void TruncateAllPageRevisions(string confirm) { if (confirm != "YES") //Are you REALLY sure? { return; } else { ManagedDataStorage.Pages.Ephemeral(o => { var transaction = o.BeginTransaction(); try { o.Execute("TruncateAllPageRevisions.sql"); transaction.Commit(); } catch { transaction.Rollback(); throw; } }); } } public static int GetCurrentPageRevision(int pageId) { var param = new { PageId = pageId, }; return ManagedDataStorage.Pages.ExecuteScalar("GetCurrentPageRevision.sql", param); } public static int GetCurrentPageRevision(ManagedDataStorageInstance connection, int pageId) { var param = new { PageId = pageId, }; return connection.ExecuteScalar("GetCurrentPageRevision.sql", param); } public static Page? GetLimitedPageInfoByIdAndRevision(int pageId, int? revision = null, bool allowCache = true) { if (allowCache) { var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Page, [pageId, revision]); if (!WikiCache.TryGet(cacheKey, out var result)) { if ((result = GetLimitedPageInfoByIdAndRevision(pageId, revision, false)) != null) { WikiCache.Put(cacheKey, result); } } return result; } var param = new { PageId = pageId, Revision = revision }; return ManagedDataStorage.Pages.QuerySingleOrDefault("GetLimitedPageInfoByIdAndRevision.sql", param); } public static int SavePage(Page page) { var pageUpsertParam = new { PageId = page.Id, Name = page.Name, Navigation = NamespaceNavigation.CleanAndValidate(page.Name), Description = page.Description, Body = page.Body ?? string.Empty, Namespace = page.Namespace, CreatedByUserId = page.CreatedByUserId, CreatedDate = page.CreatedDate, ModifiedByUserId = page.ModifiedByUserId, ModifiedDate = DateTime.UtcNow }; var newDataHash = Security.Helpers.Crc32(page.Body ?? string.Empty); ManagedDataStorage.Pages.Ephemeral(o => { var transaction = o.BeginTransaction(); try { var currentPageRevision = 0; var hasPageChanged = false; if (page.Id == 0) { page.Id = o.ExecuteScalar("CreatePage.sql", pageUpsertParam); hasPageChanged = true; } else { var currentRevisionInfo = GetLimitedPageInfoByIdAndRevision(page.Id) ?? throw new Exception("The page could not be found."); currentPageRevision = currentRevisionInfo.Revision; o.Execute("UpdatePage.sql", pageUpsertParam); hasPageChanged = currentRevisionInfo.Name != page.Name || currentRevisionInfo.Namespace != page.Namespace || currentRevisionInfo.Description != page.Description || currentRevisionInfo.DataHash != newDataHash; } if (hasPageChanged) { currentPageRevision++; var updatePageRevisionNumberParam = new { PageId = page.Id, PageRevision = currentPageRevision }; o.Execute("UpdatePageRevisionNumber.sql", updatePageRevisionNumberParam); var InsertPageRevisionParam = new { PageId = page.Id, Name = page.Name, Namespace = page.Namespace, Description = page.Description, Body = page.Body, DataHash = newDataHash, PageRevision = currentPageRevision, ModifiedByUserId = page.ModifiedByUserId, ModifiedDate = DateTime.UtcNow, }; o.Execute("InsertPageRevision.sql", InsertPageRevisionParam); var reassociateAllPageAttachmentsParam = new { PageId = page.Id, PageRevision = currentPageRevision, }; o.Execute("ReassociateAllPageAttachments.sql", reassociateAllPageAttachmentsParam); } transaction.Commit(); } catch { transaction.Rollback(); throw; } }); return page.Id; } /// /// /// /// /// public static Page? GetPageInfoByNavigation(string navigation) { var param = new { Navigation = navigation }; return ManagedDataStorage.Pages.QuerySingleOrDefault("GetPageInfoByNavigation.sql", param); } public static int GetPageRevisionCountByPageId(int pageId) { var param = new { PageId = pageId }; return ManagedDataStorage.Pages.ExecuteScalar("GetPageRevisionCountByNavigation.sql", param); } public static void RestoreDeletedPageByPageId(int pageId) { var param = new { PageId = pageId }; ManagedDataStorage.Pages.Ephemeral(o => { var transaction = o.BeginTransaction(); try { using var deletedpages_db = o.Attach("deletedpages.db", "deletedpages_db"); o.Execute("RestoreDeletedPageByPageId.sql", param); transaction.Commit(); } catch { transaction.Rollback(); throw; } }); FlushPageCache(pageId); } public static void MovePageRevisionToDeletedById(int pageId, int revision, Guid userId) { var param = new { PageId = pageId, Revision = revision, DeletedByUserId = userId, DeletedDate = DateTime.UtcNow }; ManagedDataStorage.Pages.Ephemeral(o => { var transaction = o.BeginTransaction(); try { using var deletedpagerevisions_db = o.Attach("deletedpagerevisions.db", "deletedpagerevisions_db"); o.Execute("MovePageRevisionToDeletedById.sql", param); transaction.Commit(); } catch { transaction.Rollback(); throw; } }); FlushPageCache(pageId); } public static void MovePageToDeletedById(int pageId, Guid userId) { var param = new { PageId = pageId, DeletedByUserId = userId, DeletedDate = DateTime.UtcNow }; ManagedDataStorage.Pages.Ephemeral(o => { var transaction = o.BeginTransaction(); try { using var deletedpages_db = o.Attach("deletedpages.db", "deletedpages_db"); o.Execute("MovePageToDeletedById.sql", param); transaction.Commit(); ManagedDataStorage.Statistics.Execute("DeletePageStatisticsByPageId.sql", param); } catch { transaction.Rollback(); throw; } }); FlushPageCache(pageId); } public static void PurgeDeletedPageByPageId(int pageId) { var param = new { PageId = pageId }; ManagedDataStorage.DeletedPages.Execute("PurgeDeletedPageByPageId.sql", param); PurgeDeletedPageRevisionsByPageId(pageId); FlushPageCache(pageId); } public static void PurgeDeletedPages() { ManagedDataStorage.DeletedPages.Execute("PurgeDeletedPages.sql"); PurgeDeletedPageRevisions(); } public static int GetCountOfPageAttachmentsById(int pageId) { var param = new { PageId = pageId }; return ManagedDataStorage.Pages.ExecuteScalar("GetCountOfPageAttachmentsById.sql", param); } public static Page? GetDeletedPageById(int pageId) { var param = new { PageId = pageId }; return ManagedDataStorage.DeletedPages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); return o.QuerySingleOrDefault("GetDeletedPageById.sql", param); }); } public static Page? GetLatestPageRevisionById(int pageId) { var param = new { PageId = pageId }; return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); return o.QuerySingleOrDefault("GetLatestPageRevisionById.sql", param); }); } public static int GetPageNextRevision(int pageId, int revision) { var param = new { PageId = pageId, Revision = revision }; return ManagedDataStorage.Pages.ExecuteScalar("GetPageNextRevision.sql", param); } public static int GetPagePreviousRevision(int pageId, int revision) { var param = new { PageId = pageId, Revision = revision }; return ManagedDataStorage.Pages.ExecuteScalar("GetPagePreviousRevision.sql", param); } public static List GetDeletedPageRevisionsByIdPaged(int pageId, int pageNumber, string? orderBy = null, string? orderByDirection = null) { int pageSize = ConfigurationRepository.Get("Customization", "Pagination Size"); var param = new { PageId = pageId, PageNumber = pageNumber, PageSize = pageSize }; return ManagedDataStorage.DeletedPageRevisions.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); var query = RepositoryHelper.TransposeOrderby("GetDeletedPageRevisionsByIdPaged.sql", orderBy, orderByDirection); return o.Query(query, param).ToList(); }); } public static void PurgeDeletedPageRevisions() { ManagedDataStorage.DeletedPageRevisions.Execute("PurgeDeletedPageRevisions.sql"); } public static void PurgeDeletedPageRevisionsByPageId(int pageId) { var param = new { PageId = pageId }; ManagedDataStorage.DeletedPageRevisions.Execute("PurgeDeletedPageRevisionsByPageId.sql", param); FlushPageCache(pageId); } public static void PurgeDeletedPageRevisionByPageIdAndRevision(int pageId, int revision) { var param = new { PageId = pageId, Revision = revision }; ManagedDataStorage.DeletedPageRevisions.Execute("PurgeDeletedPageRevisionByPageIdAndRevision.sql", param); FlushPageCache(pageId); } public static void RestoreDeletedPageRevisionByPageIdAndRevision(int pageId, int revision) { var param = new { PageId = pageId, Revision = revision }; ManagedDataStorage.DeletedPageRevisions.Ephemeral(o => { using var users_db = o.Attach("pages.db", "pages_db"); o.Execute("RestoreDeletedPageRevisionByPageIdAndRevision.sql", param); }); FlushPageCache(pageId); } public static DeletedPageRevision? GetDeletedPageRevisionById(int pageId, int revision) { var param = new { PageId = pageId, Revision = revision }; return ManagedDataStorage.DeletedPageRevisions.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); return o.Query("GetDeletedPageRevisionById.sql", param).FirstOrDefault(); }); } public static Page? GetPageRevisionByNavigation(NamespaceNavigation navigation, int? revision = null) { var param = new { Navigation = navigation.Canonical, Revision = revision }; return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); return o.QuerySingleOrDefault("GetPageRevisionByNavigation.sql", param); }); } public static Page? GetPageRevisionByNavigation(string givenNavigation, int? revision = null, bool allowCache = true) { var navigation = new NamespaceNavigation(givenNavigation); if (allowCache) { var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Page, [navigation.Canonical, revision]); if (!WikiCache.TryGet(cacheKey, out var result)) { if ((result = GetPageRevisionByNavigation(navigation.Canonical, revision, false)) != null) { WikiCache.Put(cacheKey, result); } } return result; } var param = new { Navigation = navigation.Canonical, Revision = revision }; return ManagedDataStorage.Pages.Ephemeral(o => { using var users_db = o.Attach("users.db", "users_db"); return o.QuerySingleOrDefault("GetPageRevisionByNavigation.sql", param); }); } #region Tags. public static List GetAssociatedTags(string tag) { var param = new { @Tag = tag }; return ManagedDataStorage.Pages.Query("GetAssociatedTags.sql", param).ToList(); } public static List GetPageInfoByNamespaces(List namespaces) { return ManagedDataStorage.Pages.Ephemeral(o => { using var tempTable = o.CreateTempTableFrom("TempNamespaces", namespaces); return o.Query("GetPageInfoByNamespaces.sql").ToList(); }); } public static List GetPageInfoByTags(List tags) { return ManagedDataStorage.Pages.Ephemeral(o => { using var tempTable = o.CreateTempTableFrom("TempTags", tags); return o.Query("GetPageInfoByTags.sql").ToList(); }); } public static List GetPageInfoByTag(string tag) { return ManagedDataStorage.Pages.Ephemeral(o => { using var tempTable = o.CreateTempTableFrom("TempTags", new List { tag }); return o.Query("GetPageInfoByTags.sql").ToList(); }); } public static void UpdatePageTags(int pageId, List tags) { ManagedDataStorage.Pages.Ephemeral(o => { tags = tags.Select(o => o.ToLower()).Distinct().ToList(); using var tempTable = o.CreateTempTableFrom("TempTags", tags); var param = new { PageId = pageId }; return o.Query("UpdatePageTags.sql", param).ToList(); }); } #endregion } }