using NPoco;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Cms.Infrastructure.Scoping;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement;
internal class DocumentVersionRepository : IDocumentVersionRepository
{
private readonly IScopeAccessor _scopeAccessor;
public DocumentVersionRepository(IScopeAccessor scopeAccessor) =>
_scopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor));
///
///
/// Never includes current draft version.
/// Never includes current published version.
/// Never includes versions marked as "preventCleanup".
///
public IReadOnlyCollection? GetDocumentVersionsEligibleForCleanup()
{
Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql();
query?.Select(@"umbracoDocument.nodeId as contentId,
umbracoContent.contentTypeId as contentTypeId,
umbracoContentVersion.id as versionId,
umbracoContentVersion.userId as userId,
umbracoContentVersion.versionDate as versionDate,
umbracoDocumentVersion.published as currentPublishedVersion,
umbracoContentVersion.[current] as currentDraftVersion,
umbracoContentVersion.preventCleanup as preventCleanup,
umbracoUser.userName as username")
.From()
.InnerJoin()
.On(left => left.NodeId, right => right.NodeId)
.InnerJoin()
.On(left => left.NodeId, right => right.NodeId)
.InnerJoin()
.On(left => left.Id, right => right.Id)
.LeftJoin()
.On(left => left.Id, right => right.UserId)
.Where(x => !x.Current) // Never delete current draft version
.Where(x => !x.PreventCleanup) // Never delete "pinned" versions
.Where(x => !x.Published); // Never delete published version
return _scopeAccessor.AmbientScope?.Database.Fetch(query);
}
///
public IReadOnlyCollection? GetCleanupPolicies()
{
Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql();
query?.Select()
.From();
return _scopeAccessor.AmbientScope?.Database.Fetch(query);
}
///
public IEnumerable? GetPagedItemsByContentId(int contentId, long pageIndex, int pageSize, out long totalRecords, int? languageId = null)
{
Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql();
query?.Select(@"umbracoDocument.nodeId as contentId,
umbracoContent.contentTypeId as contentTypeId,
umbracoContentVersion.id as versionId,
umbracoContentVersion.userId as userId,
umbracoContentVersion.versionDate as versionDate,
umbracoDocumentVersion.published as currentPublishedVersion,
umbracoContentVersion.[current] as currentDraftVersion,
umbracoContentVersion.preventCleanup as preventCleanup,
umbracoUser.userName as username")
.From()
.InnerJoin()
.On(left => left.NodeId, right => right.NodeId)
.InnerJoin()
.On(left => left.NodeId, right => right.NodeId)
.InnerJoin()
.On(left => left.Id, right => right.Id)
.LeftJoin()
.On(left => left.Id, right => right.UserId)
.LeftJoin()
.On(left => left.VersionId, right => right.Id)
.Where(x => x.NodeId == contentId);
// TODO: If there's not a better way to write this then we need a better way to write this.
query = languageId.HasValue
? query?.Where(x => x.LanguageId == languageId.Value)
: query?.Where("umbracoContentVersionCultureVariation.languageId is null");
query = query?.OrderByDescending(x => x.Id);
Page? page =
_scopeAccessor.AmbientScope?.Database.Page(pageIndex + 1, pageSize, query);
totalRecords = page?.TotalItems ?? 0;
return page?.Items;
}
///
///
/// Deletes in batches of
///
public void DeleteVersions(IEnumerable versionIds)
{
foreach (IEnumerable group in versionIds.InGroupsOf(Constants.Sql.MaxParameterCount))
{
var groupedVersionIds = group.ToList();
/* Note: We had discussed doing this in a single SQL Command.
* If you can work out how to make that work with SQL CE, let me know!
* Can use test PerformContentVersionCleanup_WithNoKeepPeriods_DeletesEverythingExceptActive to try things out.
*/
Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql()
.Delete()
.WhereIn(x => x.VersionId, groupedVersionIds);
_scopeAccessor.AmbientScope?.Database.Execute(query);
query = _scopeAccessor.AmbientScope?.SqlContext.Sql()
.Delete()
.WhereIn(x => x.VersionId, groupedVersionIds);
_scopeAccessor.AmbientScope?.Database.Execute(query);
query = _scopeAccessor.AmbientScope?.SqlContext.Sql()
.Delete()
.WhereIn(x => x.Id, groupedVersionIds);
_scopeAccessor.AmbientScope?.Database.Execute(query);
query = _scopeAccessor.AmbientScope?.SqlContext.Sql()
.Delete()
.WhereIn(x => x.Id, groupedVersionIds);
_scopeAccessor.AmbientScope?.Database.Execute(query);
}
}
///
public void SetPreventCleanup(int versionId, bool preventCleanup)
{
Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql()
.Update(x => x.Set(y => y.PreventCleanup, preventCleanup))
.Where(x => x.Id == versionId);
_scopeAccessor.AmbientScope?.Database.Execute(query);
}
///
public ContentVersionMeta? Get(int versionId)
{
Sql? query = _scopeAccessor.AmbientScope?.SqlContext.Sql();
query?.Select(@"umbracoDocument.nodeId as contentId,
umbracoContent.contentTypeId as contentTypeId,
umbracoContentVersion.id as versionId,
umbracoContentVersion.userId as userId,
umbracoContentVersion.versionDate as versionDate,
umbracoDocumentVersion.published as currentPublishedVersion,
umbracoContentVersion.[current] as currentDraftVersion,
umbracoContentVersion.preventCleanup as preventCleanup,
umbracoUser.userName as username")
.From()
.InnerJoin()
.On(left => left.NodeId, right => right.NodeId)
.InnerJoin()
.On(left => left.NodeId, right => right.NodeId)
.InnerJoin()
.On(left => left.Id, right => right.Id)
.LeftJoin()
.On(left => left.Id, right => right.UserId)
.Where(x => x.Id == versionId);
return _scopeAccessor.AmbientScope?.Database.Single(query);
}
}