mirror of https://github.com/Squidex/squidex.git
11 changed files with 290 additions and 6 deletions
@ -0,0 +1,40 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoAssetStatsEntity.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using MongoDB.Bson; |
||||
|
using MongoDB.Bson.Serialization.Attributes; |
||||
|
using Squidex.Read.Assets; |
||||
|
|
||||
|
namespace Squidex.Read.MongoDb.Assets |
||||
|
{ |
||||
|
public sealed class MongoAssetStatsEntity : IAssetStatsEntity |
||||
|
{ |
||||
|
[BsonId] |
||||
|
[BsonElement] |
||||
|
[BsonRepresentation(BsonType.String)] |
||||
|
public string Id { get; set; } |
||||
|
|
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
[BsonDateTimeOptions(DateOnly = true)] |
||||
|
public DateTime Date { get; set; } |
||||
|
|
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public Guid AppId { get; set; } |
||||
|
|
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public long TotalSize { get; set; } |
||||
|
|
||||
|
[BsonRequired] |
||||
|
[BsonElement] |
||||
|
public long TotalCount { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,91 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoAssetStatsRepository.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using MongoDB.Driver; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
using Squidex.Infrastructure.MongoDb; |
||||
|
using Squidex.Read.Assets; |
||||
|
using Squidex.Read.Assets.Repositories; |
||||
|
|
||||
|
namespace Squidex.Read.MongoDb.Assets |
||||
|
{ |
||||
|
public partial class MongoAssetStatsRepository : MongoRepositoryBase<MongoAssetStatsEntity>, IAssetStatsRepository, IEventConsumer |
||||
|
{ |
||||
|
public MongoAssetStatsRepository(IMongoDatabase database) |
||||
|
: base(database) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected override string CollectionName() |
||||
|
{ |
||||
|
return "Projections_AssetStats"; |
||||
|
} |
||||
|
|
||||
|
protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetStatsEntity> collection) |
||||
|
{ |
||||
|
return Task.WhenAll( |
||||
|
collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.AppId).Ascending(x => x.Date)), |
||||
|
collection.Indexes.CreateOneAsync(IndexKeys.Ascending(x => x.AppId).Descending(x => x.Date))); |
||||
|
} |
||||
|
|
||||
|
public async Task<IReadOnlyList<IAssetStatsEntity>> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate) |
||||
|
{ |
||||
|
var originalSizes = await Collection.Find(x => x.AppId == appId && x.Date >= fromDate && x.Date <= toDate).SortBy(x => x.Date).ToListAsync(); |
||||
|
var enrichedSizes = new List<MongoAssetStatsEntity>(); |
||||
|
|
||||
|
var sizesDictionary = originalSizes.ToDictionary(x => x.Date); |
||||
|
|
||||
|
var previousSize = long.MinValue; |
||||
|
var previousCount = long.MinValue; |
||||
|
|
||||
|
for (var date = fromDate; date <= toDate; date = date.AddDays(1)) |
||||
|
{ |
||||
|
var size = sizesDictionary.GetOrDefault(date); |
||||
|
|
||||
|
if (size != null) |
||||
|
{ |
||||
|
previousSize = size.TotalSize; |
||||
|
previousCount = size.TotalCount; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (previousSize < 0) |
||||
|
{ |
||||
|
var firstBeforeRange = await Collection.Find(x => x.AppId == appId && x.Date < fromDate).SortByDescending(x => x.Date).FirstOrDefaultAsync(); |
||||
|
|
||||
|
previousSize = firstBeforeRange?.TotalSize ?? 0L; |
||||
|
previousCount = firstBeforeRange?.TotalCount ?? 0L; |
||||
|
} |
||||
|
|
||||
|
size = new MongoAssetStatsEntity |
||||
|
{ |
||||
|
Date = date, |
||||
|
TotalSize = previousSize, |
||||
|
TotalCount = previousCount |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
enrichedSizes.Add(size); |
||||
|
} |
||||
|
|
||||
|
return enrichedSizes; |
||||
|
} |
||||
|
|
||||
|
public async Task<long> GetTotalSizeAsync(Guid appId) |
||||
|
{ |
||||
|
var entity = await Collection.Find(x => x.AppId == appId).SortByDescending(x => x.Date).FirstOrDefaultAsync(); |
||||
|
|
||||
|
return entity?.TotalSize ?? 0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
// ==========================================================================
|
||||
|
// MongoAssetStatsRepository_EventHandling.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using MongoDB.Driver; |
||||
|
using Squidex.Events.Assets; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
using Squidex.Infrastructure.Dispatching; |
||||
|
|
||||
|
namespace Squidex.Read.MongoDb.Assets |
||||
|
{ |
||||
|
public partial class MongoAssetStatsRepository |
||||
|
{ |
||||
|
private static readonly UpdateOptions Upsert = new UpdateOptions { IsUpsert = true }; |
||||
|
|
||||
|
public string Name |
||||
|
{ |
||||
|
get { return GetType().Name; } |
||||
|
} |
||||
|
|
||||
|
public string EventsFilter |
||||
|
{ |
||||
|
get { return "^asset-"; } |
||||
|
} |
||||
|
|
||||
|
public Task On(Envelope<IEvent> @event) |
||||
|
{ |
||||
|
return this.DispatchActionAsync(@event.Payload, @event.Headers); |
||||
|
} |
||||
|
|
||||
|
protected Task On(AssetCreated @event, EnvelopeHeaders headers) |
||||
|
{ |
||||
|
return UpdateSizeAsync(@event.AppId.Id, headers.Timestamp().ToDateTimeUtc().Date, @event.FileSize, 1); |
||||
|
} |
||||
|
|
||||
|
protected Task On(AssetUpdated @event, EnvelopeHeaders headers) |
||||
|
{ |
||||
|
return UpdateSizeAsync(@event.AppId.Id, headers.Timestamp().ToDateTimeUtc().Date, @event.FileSize, 0); |
||||
|
} |
||||
|
|
||||
|
protected Task On(AssetDeleted @event, EnvelopeHeaders headers) |
||||
|
{ |
||||
|
return UpdateSizeAsync(@event.AppId.Id, headers.Timestamp().ToDateTimeUtc().Date, -@event.DeletedSize, -1); |
||||
|
} |
||||
|
|
||||
|
private async Task UpdateSizeAsync(Guid appId, DateTime date, long size, long count) |
||||
|
{ |
||||
|
var id = $"{appId}_{date:yyyy-MM-dd}"; |
||||
|
|
||||
|
var entity = await Collection.Find(x => x.Id == id).FirstOrDefaultAsync(); |
||||
|
|
||||
|
if (entity == null) |
||||
|
{ |
||||
|
var last = await Collection.Find(x => x.AppId == appId).SortByDescending(x => x.Date).FirstOrDefaultAsync(); |
||||
|
|
||||
|
entity = new MongoAssetStatsEntity |
||||
|
{ |
||||
|
Id = id, |
||||
|
Date = date, |
||||
|
AppId = appId, |
||||
|
TotalSize = last?.TotalSize ?? 0, |
||||
|
TotalCount = last?.TotalCount ?? 0 |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
entity.TotalSize += size; |
||||
|
entity.TotalCount += count; |
||||
|
|
||||
|
await Collection.ReplaceOneAsync(x => x.Id == id, entity, Upsert); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
// ==========================================================================
|
||||
|
// IAssetDaySizeEntity.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace Squidex.Read.Assets |
||||
|
{ |
||||
|
public interface IAssetStatsEntity |
||||
|
{ |
||||
|
DateTime Date { get; } |
||||
|
|
||||
|
long TotalSize { get; } |
||||
|
|
||||
|
long TotalCount { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
// ==========================================================================
|
||||
|
// IAssetDaySizeRepository.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Squidex.Read.Assets.Repositories |
||||
|
{ |
||||
|
public interface IAssetStatsRepository |
||||
|
{ |
||||
|
Task<IReadOnlyList<IAssetStatsEntity>> QueryAsync(Guid appId, DateTime fromDate, DateTime toDate); |
||||
|
|
||||
|
Task<long> GetTotalSizeAsync(Guid appId); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue