mirror of https://github.com/Squidex/squidex.git
Browse Source
* References endpoints. * Tests fixed. * Mini fix. * Some fallback changes.pull/607/head
committed by
GitHub
47 changed files with 965 additions and 944 deletions
@ -1,40 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using MongoDB.Bson.Serialization; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents |
|||
{ |
|||
internal static class Fields |
|||
{ |
|||
private static readonly Lazy<string> IdField = new Lazy<string>(GetIdField); |
|||
private static readonly Lazy<string> SchemaIdField = new Lazy<string>(GetSchemaIdField); |
|||
private static readonly Lazy<string> StatusField = new Lazy<string>(GetStatusField); |
|||
|
|||
public static string Id => IdField.Value; |
|||
|
|||
public static string SchemaId => SchemaIdField.Value; |
|||
|
|||
public static string Status => StatusField.Value; |
|||
|
|||
private static string GetIdField() |
|||
{ |
|||
return BsonClassMap.LookupClassMap(typeof(MongoContentEntity)).GetMemberMap(nameof(MongoContentEntity.Id)).ElementName; |
|||
} |
|||
|
|||
private static string GetSchemaIdField() |
|||
{ |
|||
return BsonClassMap.LookupClassMap(typeof(MongoContentEntity)).GetMemberMap(nameof(MongoContentEntity.IndexedSchemaId)).ElementName; |
|||
} |
|||
|
|||
private static string GetStatusField() |
|||
{ |
|||
return BsonClassMap.LookupClassMap(typeof(MongoContentEntity)).GetMemberMap(nameof(MongoContentEntity.Status)).ElementName; |
|||
} |
|||
} |
|||
} |
|||
@ -1,138 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Core.Contents; |
|||
using Squidex.Domain.Apps.Entities.Apps; |
|||
using Squidex.Domain.Apps.Entities.Contents; |
|||
using Squidex.Domain.Apps.Entities.Contents.Text; |
|||
using Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations; |
|||
using Squidex.Domain.Apps.Entities.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
using Squidex.Infrastructure.Queries; |
|||
using Squidex.Log; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents |
|||
{ |
|||
public sealed class MongoContentCollectionPublished : MongoRepositoryBase<MongoContentEntity> |
|||
{ |
|||
private readonly QueryContent queryContentAsync; |
|||
private readonly QueryContentsByIds queryContentsById; |
|||
private readonly QueryContentsByQuery queryContentsByQuery; |
|||
private readonly QueryIdsAsync queryIdsAsync; |
|||
private readonly QueryReferrersAsync queryReferrersAsync; |
|||
|
|||
public MongoContentCollectionPublished(IMongoDatabase database, IAppProvider appProvider, ITextIndex indexer, DataConverter converter) |
|||
: base(database) |
|||
{ |
|||
queryContentAsync = new QueryContent(converter); |
|||
queryContentsById = new QueryContentsByIds(converter, appProvider); |
|||
queryContentsByQuery = new QueryContentsByQuery(converter, indexer, appProvider); |
|||
queryReferrersAsync = new QueryReferrersAsync(); |
|||
queryIdsAsync = new QueryIdsAsync(appProvider); |
|||
} |
|||
|
|||
public IMongoCollection<MongoContentEntity> GetInternalCollection() |
|||
{ |
|||
return Collection; |
|||
} |
|||
|
|||
protected override MongoCollectionSettings CollectionSettings() |
|||
{ |
|||
return new MongoCollectionSettings |
|||
{ |
|||
ReadPreference = ReadPreference.SecondaryPreferred.With(TimeSpan.FromMinutes(2)) |
|||
}; |
|||
} |
|||
|
|||
protected override string CollectionName() |
|||
{ |
|||
return "States_Contents_Published2"; |
|||
} |
|||
|
|||
protected override async Task SetupCollectionAsync(IMongoCollection<MongoContentEntity> collection, CancellationToken ct = default) |
|||
{ |
|||
await queryContentAsync.PrepareAsync(collection, ct); |
|||
await queryContentsById.PrepareAsync(collection, ct); |
|||
await queryContentsByQuery.PrepareAsync(collection, ct); |
|||
await queryReferrersAsync.PrepareAsync(collection, ct); |
|||
await queryIdsAsync.PrepareAsync(collection, ct); |
|||
} |
|||
|
|||
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, ClrQuery query, DomainId? referenced) |
|||
{ |
|||
using (Profiler.TraceMethod<MongoContentRepository>("QueryAsyncByQuery")) |
|||
{ |
|||
return await queryContentsByQuery.DoAsync(app, schema, query, referenced, SearchScope.Published); |
|||
} |
|||
} |
|||
|
|||
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, HashSet<DomainId> ids) |
|||
{ |
|||
Guard.NotNull(app, nameof(app)); |
|||
|
|||
using (Profiler.TraceMethod<MongoContentRepository>("QueryAsyncByIds")) |
|||
{ |
|||
var result = await queryContentsById.DoAsync(app.Id, schema, ids, true); |
|||
|
|||
return ResultList.Create(result.Count, result.Select(x => x.Content)); |
|||
} |
|||
} |
|||
|
|||
public async Task<List<(IContentEntity Content, ISchemaEntity Schema)>> QueryAsync(IAppEntity app, HashSet<DomainId> ids) |
|||
{ |
|||
Guard.NotNull(app, nameof(app)); |
|||
|
|||
using (Profiler.TraceMethod<MongoContentRepository>("QueryAsyncByIdsWithoutSchema")) |
|||
{ |
|||
var result = await queryContentsById.DoAsync(app.Id, null, ids, true); |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
|
|||
public async Task<IContentEntity?> FindContentAsync(ISchemaEntity schema, DomainId id) |
|||
{ |
|||
using (Profiler.TraceMethod<MongoContentRepository>()) |
|||
{ |
|||
return await queryContentAsync.DoAsync(schema, id); |
|||
} |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids) |
|||
{ |
|||
using (Profiler.TraceMethod<MongoContentRepository>()) |
|||
{ |
|||
return await queryIdsAsync.DoAsync(appId, ids); |
|||
} |
|||
} |
|||
|
|||
public async Task<bool> HasReferrersAsync(DomainId appId, DomainId contentId) |
|||
{ |
|||
using (Profiler.TraceMethod<MongoContentRepository>()) |
|||
{ |
|||
return await queryReferrersAsync.DoAsync(appId, contentId); |
|||
} |
|||
} |
|||
|
|||
public Task UpsertVersionedAsync(DomainId documentId, long oldVersion, MongoContentEntity entity) |
|||
{ |
|||
return Collection.UpsertVersionedAsync(documentId, oldVersion, entity.Version, entity); |
|||
} |
|||
|
|||
public Task RemoveAsync(DomainId documentId) |
|||
{ |
|||
return Collection.DeleteOneAsync(x => x.DocumentId == documentId); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Bson.Serialization.Attributes; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Core.Contents; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations |
|||
{ |
|||
public static class Extensions |
|||
{ |
|||
public sealed class StatusModel |
|||
{ |
|||
[BsonId] |
|||
[BsonElement("_id")] |
|||
public DomainId DocumentId { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement("id")] |
|||
public DomainId Id { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement("_si")] |
|||
public DomainId IndexedSchemaId { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement("ss")] |
|||
public Status Status { get; set; } |
|||
} |
|||
|
|||
public static Task<List<StatusModel>> FindStatusAsync(this IMongoCollection<MongoContentEntity> collection, FilterDefinition<MongoContentEntity> filter) |
|||
{ |
|||
var projections = Builders<MongoContentEntity>.Projection; |
|||
|
|||
return collection.Find(filter) |
|||
.Project<StatusModel>(projections |
|||
.Include(x => x.Id) |
|||
.Include(x => x.IndexedSchemaId) |
|||
.Include(x => x.Status)) |
|||
.ToListAsync(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Entities.Contents; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations |
|||
{ |
|||
public sealed class QueryAsStream : OperationBase |
|||
{ |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public QueryAsStream(DataConverter converter, IAppProvider appProvider) |
|||
: base(converter) |
|||
{ |
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
protected override async Task PrepareAsync(CancellationToken ct = default) |
|||
{ |
|||
var indexBySchema = |
|||
new CreateIndexModel<MongoContentEntity>(Index |
|||
.Ascending(x => x.IndexedAppId) |
|||
.Ascending(x => x.IsDeleted) |
|||
.Ascending(x => x.IndexedSchemaId)); |
|||
|
|||
await Collection.Indexes.CreateOneAsync(indexBySchema, cancellationToken: ct); |
|||
} |
|||
|
|||
public async IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds) |
|||
{ |
|||
var find = |
|||
schemaIds != null ? |
|||
Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && schemaIds.Contains(x.IndexedSchemaId)) : |
|||
Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted); |
|||
|
|||
using (var cursor = await find.ToCursorAsync()) |
|||
{ |
|||
while (await cursor.MoveNextAsync()) |
|||
{ |
|||
foreach (var entity in cursor.Current) |
|||
{ |
|||
var schema = await appProvider.GetSchemaAsync(appId, entity.SchemaId.Id, false); |
|||
|
|||
if (schema != null) |
|||
{ |
|||
entity.ParseData(schema.SchemaDef, DataConverter); |
|||
|
|||
yield return entity; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Core.Contents; |
|||
using Squidex.Domain.Apps.Entities.Contents; |
|||
using Squidex.Domain.Apps.Entities.Schemas; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.MongoDb.Queries; |
|||
using Squidex.Infrastructure.Queries; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations |
|||
{ |
|||
internal sealed class QueryByIds : OperationBase |
|||
{ |
|||
public QueryByIds(DataConverter dataConverter) |
|||
: base(dataConverter) |
|||
{ |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, HashSet<DomainId> ids) |
|||
{ |
|||
if (ids == null || ids.Count == 0) |
|||
{ |
|||
return new List<(DomainId SchemaId, DomainId Id, Status Status)>(); |
|||
} |
|||
|
|||
var filter = CreateFilter(appId, null, ids); |
|||
|
|||
var contentItems = await Collection.FindStatusAsync(filter); |
|||
|
|||
return contentItems.Select(x => (x.IndexedSchemaId, x.Id, x.Status)).ToList(); |
|||
} |
|||
|
|||
public async Task<IResultList<IContentEntity>> QueryAsync(DomainId appId, List<ISchemaEntity> schemas, Q q) |
|||
{ |
|||
Guard.NotNull(q, nameof(q)); |
|||
|
|||
if (q.Ids == null || q.Ids.Count == 0) |
|||
{ |
|||
return ResultList.CreateFrom<IContentEntity>(0); |
|||
} |
|||
|
|||
var filter = CreateFilter(appId, schemas.Select(x => x.Id), q.Ids.ToHashSet()); |
|||
|
|||
var items = await FindContentsAsync(q.Query, filter); |
|||
|
|||
if (items.Count > 0) |
|||
{ |
|||
var contentSchemas = schemas.ToDictionary(x => x.Id); |
|||
|
|||
foreach (var content in items) |
|||
{ |
|||
var schema = contentSchemas[content.SchemaId.Id]; |
|||
|
|||
content.ParseData(schema.SchemaDef, DataConverter); |
|||
} |
|||
} |
|||
|
|||
return ResultList.Create(items.Count, items); |
|||
} |
|||
|
|||
private async Task<List<MongoContentEntity>> FindContentsAsync(ClrQuery query, FilterDefinition<MongoContentEntity> filter) |
|||
{ |
|||
var result = |
|||
Collection.Find(filter) |
|||
.QueryLimit(query) |
|||
.QuerySkip(query) |
|||
.ToListAsync(); |
|||
|
|||
return await result; |
|||
} |
|||
|
|||
private static FilterDefinition<MongoContentEntity> CreateFilter(DomainId appId, IEnumerable<DomainId>? schemaIds, HashSet<DomainId> ids) |
|||
{ |
|||
var filters = new List<FilterDefinition<MongoContentEntity>>(); |
|||
|
|||
var documentIds = ids.Select(x => DomainId.Combine(appId, x)).ToList(); |
|||
|
|||
if (documentIds.Count > 1) |
|||
{ |
|||
filters.Add( |
|||
Filter.Or( |
|||
Filter.In(x => x.DocumentId, documentIds))); |
|||
} |
|||
else |
|||
{ |
|||
var first = documentIds.First(); |
|||
|
|||
filters.Add( |
|||
Filter.Or( |
|||
Filter.Eq(x => x.DocumentId, first))); |
|||
} |
|||
|
|||
if (schemaIds != null) |
|||
{ |
|||
filters.Add(Filter.In(x => x.IndexedSchemaId, schemaIds)); |
|||
} |
|||
|
|||
filters.Add(Filter.Ne(x => x.IsDeleted, true)); |
|||
|
|||
return Filter.And(filters); |
|||
} |
|||
} |
|||
} |
|||
@ -1,111 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Entities.Contents; |
|||
using Squidex.Domain.Apps.Entities.Schemas; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations |
|||
{ |
|||
internal sealed class QueryContentsByIds : OperationBase |
|||
{ |
|||
private readonly DataConverter converter; |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public QueryContentsByIds(DataConverter converter, IAppProvider appProvider) |
|||
{ |
|||
this.converter = converter; |
|||
|
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
public async Task<List<(IContentEntity Content, ISchemaEntity Schema)>> DoAsync(DomainId appId, ISchemaEntity? schema, HashSet<DomainId> ids, bool canCache) |
|||
{ |
|||
Guard.NotNull(ids, nameof(ids)); |
|||
|
|||
var find = Collection.Find(CreateFilter(appId, ids)); |
|||
|
|||
var contentItems = await find.ToListAsync(); |
|||
var contentSchemas = await GetSchemasAsync(appId, schema, contentItems, canCache); |
|||
|
|||
var result = new List<(IContentEntity Content, ISchemaEntity Schema)>(); |
|||
|
|||
foreach (var contentEntity in contentItems) |
|||
{ |
|||
if (contentSchemas.TryGetValue(contentEntity.IndexedSchemaId, out var contentSchema)) |
|||
{ |
|||
contentEntity.ParseData(contentSchema.SchemaDef, converter); |
|||
|
|||
result.Add((contentEntity, contentSchema)); |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
private async Task<IDictionary<DomainId, ISchemaEntity>> GetSchemasAsync(DomainId appId, ISchemaEntity? schema, List<MongoContentEntity> contentItems, bool canCache) |
|||
{ |
|||
var schemas = new Dictionary<DomainId, ISchemaEntity>(); |
|||
|
|||
if (schema != null) |
|||
{ |
|||
schemas[schema.Id] = schema; |
|||
} |
|||
|
|||
var schemaIds = contentItems.Select(x => x.IndexedSchemaId).Distinct(); |
|||
|
|||
foreach (var schemaId in schemaIds) |
|||
{ |
|||
if (!schemas.ContainsKey(schemaId)) |
|||
{ |
|||
var found = await appProvider.GetSchemaAsync(appId, schemaId, false, canCache); |
|||
|
|||
if (found != null) |
|||
{ |
|||
schemas[schemaId] = found; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return schemas; |
|||
} |
|||
|
|||
private static FilterDefinition<MongoContentEntity> CreateFilter(DomainId appId, ICollection<DomainId> ids) |
|||
{ |
|||
var filters = new List<FilterDefinition<MongoContentEntity>> |
|||
{ |
|||
Filter.Ne(x => x.IsDeleted, true) |
|||
}; |
|||
|
|||
if (ids != null && ids.Count > 0) |
|||
{ |
|||
var documentIds = ids.Select(x => DomainId.Combine(appId, x)).ToList(); |
|||
|
|||
if (ids.Count > 1) |
|||
{ |
|||
filters.Add( |
|||
Filter.Or( |
|||
Filter.In(x => x.DocumentId, documentIds))); |
|||
} |
|||
else |
|||
{ |
|||
var first = documentIds.First(); |
|||
|
|||
filters.Add( |
|||
Filter.Or( |
|||
Filter.Eq(x => x.DocumentId, first))); |
|||
} |
|||
} |
|||
|
|||
return Filter.And(filters); |
|||
} |
|||
} |
|||
} |
|||
@ -1,98 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Core.Contents; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
using Squidex.Infrastructure.MongoDb.Queries; |
|||
using Squidex.Infrastructure.Queries; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations |
|||
{ |
|||
internal sealed class QueryIdsAsync : OperationBase |
|||
{ |
|||
private static readonly List<(DomainId SchemaId, DomainId Id, Status Status)> EmptyIds = new List<(DomainId SchemaId, DomainId Id, Status Status)>(); |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public QueryIdsAsync(IAppProvider appProvider) |
|||
{ |
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
protected override Task PrepareAsync(CancellationToken ct = default) |
|||
{ |
|||
var index = |
|||
new CreateIndexModel<MongoContentEntity>(Index |
|||
.Ascending(x => x.IndexedAppId) |
|||
.Ascending(x => x.IndexedSchemaId) |
|||
.Ascending(x => x.IsDeleted)); |
|||
|
|||
return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct); |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> DoAsync(DomainId appId, HashSet<DomainId> ids) |
|||
{ |
|||
var documentIds = ids.Select(x => DomainId.Combine(appId, x)); |
|||
|
|||
var filter = |
|||
Filter.And( |
|||
Filter.In(x => x.DocumentId, documentIds), |
|||
Filter.Ne(x => x.IsDeleted, true)); |
|||
|
|||
return await SearchAsync(filter); |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> DoAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode) |
|||
{ |
|||
var schema = await appProvider.GetSchemaAsync(appId, schemaId, false); |
|||
|
|||
if (schema == null) |
|||
{ |
|||
return EmptyIds; |
|||
} |
|||
|
|||
var filter = BuildFilter(filterNode.AdjustToModel(schema.SchemaDef), appId, schemaId); |
|||
|
|||
return await SearchAsync(filter); |
|||
} |
|||
|
|||
private async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> SearchAsync(FilterDefinition<MongoContentEntity> filter) |
|||
{ |
|||
var contentEntities = |
|||
await Collection.Find(filter).Only(x => x.Id, x => x.IndexedSchemaId, x => x.Status) |
|||
.ToListAsync(); |
|||
|
|||
return contentEntities.Select(x => ( |
|||
DomainId.Create(x[Fields.SchemaId].AsString), |
|||
DomainId.Create(x[Fields.Id].AsString), |
|||
new Status(x[Fields.Status].AsString) |
|||
)).ToList(); |
|||
} |
|||
|
|||
private static FilterDefinition<MongoContentEntity> BuildFilter(FilterNode<ClrValue>? filterNode, DomainId appId, DomainId schemaId) |
|||
{ |
|||
var filters = new List<FilterDefinition<MongoContentEntity>> |
|||
{ |
|||
Filter.Eq(x => x.IndexedAppId, appId), |
|||
Filter.Eq(x => x.IndexedSchemaId, schemaId), |
|||
Filter.Ne(x => x.IsDeleted, true) |
|||
}; |
|||
|
|||
if (filterNode != null) |
|||
{ |
|||
filters.Add(filterNode.BuildFilter<MongoContentEntity>()); |
|||
} |
|||
|
|||
return Filter.And(filters); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Bson.Serialization.Attributes; |
|||
using MongoDB.Driver; |
|||
using Squidex.Domain.Apps.Entities.Contents; |
|||
using Squidex.Domain.Apps.Entities.Schemas; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations |
|||
{ |
|||
internal class QueryReferences : OperationBase |
|||
{ |
|||
private static readonly IResultList<IContentEntity> EmptyIds = ResultList.CreateFrom<IContentEntity>(0); |
|||
private readonly QueryByIds queryByIds; |
|||
|
|||
public sealed class ReferencedIdsOnly |
|||
{ |
|||
[BsonId] |
|||
[BsonElement("_id")] |
|||
public DomainId DocumentId { get; set; } |
|||
|
|||
[BsonRequired] |
|||
[BsonElement("rf")] |
|||
public HashSet<DomainId>? ReferencedIds { get; set; } |
|||
} |
|||
|
|||
public QueryReferences(DataConverter dataConverter, QueryByIds queryByIds) |
|||
: base(dataConverter) |
|||
{ |
|||
this.queryByIds = queryByIds; |
|||
} |
|||
|
|||
public async Task<IResultList<IContentEntity>> QueryAsync(DomainId appId, List<ISchemaEntity> schemas, Q q) |
|||
{ |
|||
var documentId = DomainId.Combine(appId, q.Referencing); |
|||
|
|||
var find = |
|||
Collection |
|||
.Find(x => x.DocumentId == documentId) |
|||
.Project<ReferencedIdsOnly>(Projection.Include(x => x.ReferencedIds)); |
|||
|
|||
var contentEntity = await find.FirstOrDefaultAsync(); |
|||
|
|||
if (contentEntity == null) |
|||
{ |
|||
throw new DomainObjectNotFoundException(q.Referencing.ToString()); |
|||
} |
|||
|
|||
if (contentEntity.ReferencedIds == null || contentEntity.ReferencedIds.Count == 0) |
|||
{ |
|||
return EmptyIds; |
|||
} |
|||
|
|||
q = q.WithReferencing(default).WithIds(contentEntity.ReferencedIds!); |
|||
|
|||
return await queryByIds.QueryAsync(appId, schemas, q); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue