Browse Source

Single endpoint for assets.

pull/214/head
Sebastian Stehle 8 years ago
parent
commit
b941d0b0e0
  1. 77
      src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs
  2. 10
      src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs
  3. 26
      src/Squidex.Domain.Apps.Entities/AppProvider.cs
  4. 5
      src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs
  5. 2
      src/Squidex.Domain.Apps.Entities/Schemas/Repositories/ISchemaRepository.cs
  6. 17
      src/Squidex.Infrastructure/IResultList.cs
  7. 31
      src/Squidex.Infrastructure/ResultList.cs
  8. 9
      src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs
  9. 4
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs

77
src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs

@ -44,40 +44,43 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
.Descending(x => x.State.LastModified)); .Descending(x => x.State.LastModified));
} }
public async Task<(AssetState Value, long Version)> ReadAsync(Guid key) public async Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null, int take = 10, int skip = 0)
{ {
var existing = var filters = new List<FilterDefinition<MongoAssetEntity>>
await Collection.Find(x => x.Id == key) {
.FirstOrDefaultAsync(); Filter.Eq(x => x.State.AppId, appId),
Filter.Eq(x => x.State.IsDeleted, false)
};
if (existing != null) if (ids != null && ids.Count > 0)
{ {
return (existing.State, existing.Version); filters.Add(Filter.In(x => x.Id, ids));
} }
return (null, EtagVersion.NotFound); if (mimeTypes != null && mimeTypes.Count > 0)
} {
filters.Add(Filter.In(x => x.State.MimeType, mimeTypes));
public async Task<IReadOnlyList<IAssetEntity>> QueryAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null, int take = 10, int skip = 0) }
{
var filter = CreateFilter(appId, mimeTypes, ids, query);
var assetEntities = if (!string.IsNullOrWhiteSpace(query))
await Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.State.LastModified) {
.ToListAsync(); filters.Add(Filter.Regex(x => x.State.FileName, new BsonRegularExpression(query, "i")));
}
return assetEntities.Select(x => x.State).ToList(); var filter = Filter.And(filters);
}
public async Task<long> CountAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null) var find = Collection.Find(filter);
{
var filter = CreateFilter(appId, mimeTypes, ids, query);
var assetsCount = var assetEntities =
await Collection.Find(filter) Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.State.LastModified)
.ToListAsync();
var assetCount =
Collection.Find(filter)
.CountAsync(); .CountAsync();
return assetsCount; await Task.WhenAll(assetEntities, assetCount);
return ResultList.Create<IAssetEntity>(assetEntities.Result.Select(x => x.State), assetCount.Result);
} }
public async Task<IAssetEntity> FindAssetAsync(Guid id) public async Task<IAssetEntity> FindAssetAsync(Guid id)
@ -87,32 +90,18 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
return state; return state;
} }
private static FilterDefinition<MongoAssetEntity> CreateFilter(Guid appId, ICollection<string> mimeTypes, ICollection<Guid> ids, string query) public async Task<(AssetState Value, long Version)> ReadAsync(Guid key)
{ {
var filters = new List<FilterDefinition<MongoAssetEntity>> var existing =
{ await Collection.Find(x => x.Id == key)
Filter.Eq(x => x.State.AppId, appId), .FirstOrDefaultAsync();
Filter.Eq(x => x.State.IsDeleted, false)
};
if (ids != null && ids.Count > 0)
{
filters.Add(Filter.In(x => x.Id, ids));
}
if (mimeTypes != null && mimeTypes.Count > 0)
{
filters.Add(Filter.In(x => x.State.MimeType, mimeTypes));
}
if (!string.IsNullOrWhiteSpace(query)) if (existing != null)
{ {
filters.Add(Filter.Regex(x => x.State.FileName, new BsonRegularExpression(query, "i"))); return (existing.State, existing.Version);
} }
var filter = Filter.And(filters); return (null, EtagVersion.NotFound);
return filter;
} }
public async Task WriteAsync(Guid key, AssetState value, long oldVersion, long newVersion) public async Task WriteAsync(Guid key, AssetState value, long oldVersion, long newVersion)

10
src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs

@ -51,13 +51,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas
return (null, EtagVersion.NotFound); return (null, EtagVersion.NotFound);
} }
public async Task<Guid> FindSchemaIdAsync(Guid appId, string name) public async Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId, string name)
{ {
var schemaEntity = var schemaEntities =
await Collection.Find(x => x.AppId == appId && x.Name == name).Only(x => x.Id) await Collection.Find(x => x.AppId == appId && x.Name == name).Only(x => x.Id).SortByDescending(x => x.Version)
.FirstOrDefaultAsync(); .ToListAsync();
return schemaEntity != null ? Guid.Parse(schemaEntity["_id"].AsString) : Guid.Empty; return schemaEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList();
} }
public async Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId) public async Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId)

26
src/Squidex.Domain.Apps.Entities/AppProvider.cs

@ -73,25 +73,22 @@ namespace Squidex.Domain.Apps.Entities
return IsNotFound(app) ? null : app.State; return IsNotFound(app) ? null : app.State;
} }
public async Task<ISchemaEntity> GetSchemaAsync(Guid appId, string name, bool provideDeleted = false) public async Task<ISchemaEntity> GetSchemaAsync(Guid appId, Guid id, bool provideDeleted = false)
{ {
var schemaId = await GetSchemaIdAsync(appId, name); var schema = await stateFactory.GetSingleAsync<SchemaDomainObject>(id);
if (schemaId == Guid.Empty)
{
return null;
}
var schema = await stateFactory.GetSingleAsync<SchemaDomainObject>(schemaId);
return IsNotFound(provideDeleted, schema) ? null : schema.State; return IsNotFound(provideDeleted, schema) ? null : schema.State;
} }
public async Task<ISchemaEntity> GetSchemaAsync(Guid appId, Guid id, bool provideDeleted = false) public async Task<ISchemaEntity> GetSchemaAsync(Guid appId, string name, bool provideDeleted = false)
{ {
var schema = await stateFactory.GetSingleAsync<SchemaDomainObject>(id); var ids = await schemaRepository.QuerySchemaIdsAsync(appId);
return IsNotFound(provideDeleted, schema) ? null : schema.State; var schemas =
await Task.WhenAll(
ids.Select(id => stateFactory.GetSingleAsync<SchemaDomainObject>(id)));
return schemas.OrderByDescending(x => x.State.LastModified).FirstOrDefault(s => IsNotFound(provideDeleted, s))?.State;
} }
public async Task<List<ISchemaEntity>> GetSchemasAsync(Guid appId) public async Task<List<ISchemaEntity>> GetSchemasAsync(Guid appId)
@ -132,11 +129,6 @@ namespace Squidex.Domain.Apps.Entities
return appRepository.FindAppIdByNameAsync(name); return appRepository.FindAppIdByNameAsync(name);
} }
private Task<Guid> GetSchemaIdAsync(Guid appId, string name)
{
return schemaRepository.FindSchemaIdAsync(appId, name);
}
private static bool IsNotFound(AppDomainObject app) private static bool IsNotFound(AppDomainObject app)
{ {
return app.Version < 0; return app.Version < 0;

5
src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs

@ -9,15 +9,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Assets.Repositories namespace Squidex.Domain.Apps.Entities.Assets.Repositories
{ {
public interface IAssetRepository public interface IAssetRepository
{ {
Task<IReadOnlyList<IAssetEntity>> QueryAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null, int take = 10, int skip = 0); Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null, int take = 10, int skip = 0);
Task<IAssetEntity> FindAssetAsync(Guid id); Task<IAssetEntity> FindAssetAsync(Guid id);
Task<long> CountAsync(Guid appId, HashSet<string> mimeTypes = null, HashSet<Guid> ids = null, string query = null);
} }
} }

2
src/Squidex.Domain.Apps.Entities/Schemas/Repositories/ISchemaRepository.cs

@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Repositories
{ {
public interface ISchemaRepository public interface ISchemaRepository
{ {
Task<Guid> FindSchemaIdAsync(Guid appId, string name); Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId, string name);
Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId); Task<IReadOnlyList<Guid>> QuerySchemaIdsAsync(Guid appId);
} }

17
src/Squidex.Infrastructure/IResultList.cs

@ -0,0 +1,17 @@
// ==========================================================================
// IResultList.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Infrastructure
{
public interface IResultList<T> : IReadOnlyList<T>
{
long Total { get; }
}
}

31
src/Squidex.Infrastructure/ResultList.cs

@ -0,0 +1,31 @@
// ==========================================================================
// ResultList.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Infrastructure
{
public static class ResultList
{
private sealed class Impl<T> : List<T>, IResultList<T>
{
public long Total { get; }
public Impl(IEnumerable<T> items, long total)
: base(items)
{
Total = total;
}
}
public static IResultList<T> Create<T>(IEnumerable<T> items, long total)
{
return new Impl<T>(items, total);
}
}
}

9
src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs

@ -102,15 +102,12 @@ namespace Squidex.Areas.Api.Controllers.Assets
} }
} }
var taskForItems = assetRepository.QueryAsync(App.Id, mimeTypeList, idsList, query, take, skip); var assets = await assetRepository.QueryAsync(App.Id, mimeTypeList, idsList, query, take, skip);
var taskForCount = assetRepository.CountAsync(App.Id, mimeTypeList, idsList, query);
await Task.WhenAll(taskForItems, taskForCount);
var response = new AssetsDto var response = new AssetsDto
{ {
Total = taskForCount.Result, Total = assets.Total,
Items = taskForItems.Result.Select(x => SimpleMapper.Map(x, new AssetDto { FileType = x.FileName.FileType() })).ToArray() Items = assets.Select(x => SimpleMapper.Map(x, new AssetDto { FileType = x.FileName.FileType() })).ToArray()
}; };
return Ok(response); return Ok(response);

4
tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs

@ -137,7 +137,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
var assets = new List<IAssetEntity> { asset }; var assets = new List<IAssetEntity> { asset };
A.CallTo(() => assetRepository.QueryAsync(app.Id, null, null, "my-query", 30, 5)) A.CallTo(() => assetRepository.QueryAsync(app.Id, null, null, "my-query", 30, 5))
.Returns(assets); .Returns(ResultList.Create(assets, 0));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query }); var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
@ -546,7 +546,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
.Returns((schema, content)); .Returns((schema, content));
A.CallTo(() => assetRepository.QueryAsync(app.Id, null, A<HashSet<Guid>>.That.Matches(x => x.Contains(assetRefId)), null, int.MaxValue, 0)) A.CallTo(() => assetRepository.QueryAsync(app.Id, null, A<HashSet<Guid>>.That.Matches(x => x.Contains(assetRefId)), null, int.MaxValue, 0))
.Returns(refAssets); .Returns(ResultList.Create(refAssets, 0));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query }); var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });

Loading…
Cancel
Save