Browse Source

Filter tag transformer for contents.

pull/320/head
Sebastian Stehle 7 years ago
parent
commit
3e543b6a38
  1. 2
      src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs
  2. 6
      src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs
  3. 13
      src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs
  4. 65
      src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs
  5. 10
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs
  6. 4
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs
  7. 99
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/FilterTagTransformerTests.cs

2
src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs

@ -89,7 +89,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
if (result.Filter != null)
{
result.Filter = QueryTagVisitor.Transform(result.Filter, context.App.Id, tagService);
result.Filter = FilterTagTransformer.Transform(result.Filter, context.App.Id, tagService);
}
if (result.Sort.Count == 0)

6
src/Squidex.Domain.Apps.Entities/Assets/Queries/QueryTagVisitor.cs → src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs

@ -13,12 +13,12 @@ using Squidex.Infrastructure.Queries;
namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
public sealed class QueryTagVisitor : TransformVisitor
public sealed class FilterTagTransformer : TransformVisitor
{
private readonly ITagService tagService;
private readonly Guid appId;
private QueryTagVisitor(Guid appId, ITagService tagService)
private FilterTagTransformer(Guid appId, ITagService tagService)
{
this.appId = appId;
@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
Guard.NotNull(tagService, nameof(tagService));
return nodeIn.Accept(new QueryTagVisitor(appId, tagService));
return nodeIn.Accept(new FilterTagTransformer(appId, tagService));
}
public override FilterNode Visit(FilterComparison nodeIn)

13
src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs

@ -13,6 +13,8 @@ using Microsoft.OData;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.ConvertContent;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.Tags;
using Squidex.Domain.Apps.Entities.Assets.Queries;
using Squidex.Domain.Apps.Entities.Contents.Edm;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
using Squidex.Domain.Apps.Entities.Schemas;
@ -37,13 +39,15 @@ namespace Squidex.Domain.Apps.Entities.Contents
private readonly IContentVersionLoader contentVersionLoader;
private readonly IAppProvider appProvider;
private readonly IScriptEngine scriptEngine;
private readonly ITagService tagService;
private readonly EdmModelBuilder modelBuilder;
public ContentQueryService(
IAppProvider appProvider,
IContentRepository contentRepository,
IContentVersionLoader contentVersionLoader,
IAppProvider appProvider,
IScriptEngine scriptEngine,
ITagService tagService,
EdmModelBuilder modelBuilder)
{
Guard.NotNull(appProvider, nameof(appProvider));
@ -51,12 +55,14 @@ namespace Squidex.Domain.Apps.Entities.Contents
Guard.NotNull(contentVersionLoader, nameof(contentVersionLoader));
Guard.NotNull(modelBuilder, nameof(modelBuilder));
Guard.NotNull(scriptEngine, nameof(scriptEngine));
Guard.NotNull(tagService, nameof(tagService));
this.appProvider = appProvider;
this.contentRepository = contentRepository;
this.contentVersionLoader = contentVersionLoader;
this.modelBuilder = modelBuilder;
this.scriptEngine = scriptEngine;
this.tagService = tagService;
}
public Task ThrowIfSchemaNotExistsAsync(ContentQueryContext context)
@ -209,6 +215,11 @@ namespace Squidex.Domain.Apps.Entities.Contents
var result = model.ParseQuery(query).ToQuery();
if (result.Filter != null)
{
result.Filter = FilterTagTransformer.Transform(result.Filter, context.App.Id, tagService);
}
if (result.Sort.Count == 0)
{
result.Sort.Add(new SortNode(new List<string> { "lastModified" }, SortOrder.Descending));

65
src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs

@ -0,0 +1,65 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Tags;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Queries;
namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
public sealed class FilterTagTransformer : TransformVisitor
{
private readonly ITagService tagService;
private readonly ISchemaEntity schema;
private readonly Guid appId;
private FilterTagTransformer(Guid appId, ISchemaEntity schema, ITagService tagService)
{
this.appId = appId;
this.schema = schema;
this.tagService = tagService;
}
public static FilterNode Transform(FilterNode nodeIn, Guid appId, ISchemaEntity schema, ITagService tagService)
{
Guard.NotNull(tagService, nameof(tagService));
Guard.NotNull(schema, nameof(schema));
return nodeIn.Accept(new FilterTagTransformer(appId, schema, tagService));
}
public override FilterNode Visit(FilterComparison nodeIn)
{
if (nodeIn.Value is string stringValue && IsDataPath(nodeIn.Path) && IsTagField(nodeIn.Path))
{
var tagNames = Task.Run(() => tagService.GetTagIdsAsync(appId, TagGroups.Schemas(schema.Id), HashSet.Of(stringValue))).Result;
if (tagNames.TryGetValue(stringValue, out var normalized))
{
return new FilterComparison(nodeIn.Path, nodeIn.Operator, normalized, FilterValueType.String);
}
}
return nodeIn;
}
private static bool IsDataPath(IReadOnlyList<string> path)
{
return path.Count == 3 && string.Equals(path[0], nameof(IContentEntity.Data), StringComparison.OrdinalIgnoreCase);
}
private bool IsTagField(IReadOnlyList<string> path)
{
return schema.SchemaDef.FieldsByName.TryGetValue(path[1], out var field) && field is IField<TagsFieldProperties> tags && tags.Properties.Normalize;
}
}
}

10
tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/QueryTagVisitorTests.cs → tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs

@ -14,7 +14,7 @@ using Xunit;
namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
public class QueryTagVisitorTests
public class FilterTagTransformerTests
{
private readonly ITagService tagService = A.Fake<ITagService>();
private readonly Guid appId = Guid.NewGuid();
@ -26,19 +26,19 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
.Returns(new Dictionary<string, string> { ["tag1"] = "normalized1" });
var source = FilterBuilder.Eq("tags", "tag1");
var result = QueryTagVisitor.Transform(source, appId, tagService);
var result = FilterTagTransformer.Transform(source, appId, tagService);
Assert.Equal("tags == normalized1", result.ToString());
}
[Fact]
public void Should_not_not_fail_when_not_found()
public void Should_not_fail_when_tags_not_found()
{
A.CallTo(() => tagService.GetTagIdsAsync(appId, TagGroups.Assets, A<HashSet<string>>.That.Contains("tag1")))
.Returns(new Dictionary<string, string>());
var source = FilterBuilder.Eq("tags", "tag1");
var result = QueryTagVisitor.Transform(source, appId, tagService);
var result = FilterTagTransformer.Transform(source, appId, tagService);
Assert.Equal("tags == tag1", result.ToString());
}
@ -47,7 +47,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
public void Should_not_normalize_other_field()
{
var source = FilterBuilder.Eq("other", "value");
var result = QueryTagVisitor.Transform(source, appId, tagService);
var result = FilterTagTransformer.Transform(source, appId, tagService);
Assert.Equal("other == value", result.ToString());

4
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs

@ -16,6 +16,7 @@ using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.Tags;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.Edm;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
@ -37,6 +38,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
private readonly ISchemaEntity schema = A.Fake<ISchemaEntity>();
private readonly IAppEntity app = A.Fake<IAppEntity>();
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly ITagService tagService = A.Fake<ITagService>();
private readonly Guid appId = Guid.NewGuid();
private readonly Guid schemaId = Guid.NewGuid();
private readonly string appName = "my-app";
@ -60,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
context = new ContentQueryContext(QueryContext.Create(app, user));
sut = new ContentQueryService(contentRepository, contentVersionLoader, appProvider, scriptEngine, modelBuilder);
sut = new ContentQueryService(appProvider, contentRepository, contentVersionLoader, scriptEngine, tagService, modelBuilder);
}
[Fact]

99
tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/FilterTagTransformerTests.cs

@ -0,0 +1,99 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using FakeItEasy;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Tags;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure.Queries;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
public class FilterTagTransformerTests
{
private readonly ITagService tagService = A.Fake<ITagService>();
private readonly ISchemaEntity schema = A.Fake<ISchemaEntity>();
private readonly Guid appId = Guid.NewGuid();
private readonly Guid schemaId = Guid.NewGuid();
public FilterTagTransformerTests()
{
var schemaDef =
new Schema("schema")
.AddTags(1, "tags1", Partitioning.Invariant)
.AddTags(2, "tags2", Partitioning.Invariant, new TagsFieldProperties { Normalize = true })
.AddString(3, "string", Partitioning.Invariant);
A.CallTo(() => schema.Id).Returns(schemaId);
A.CallTo(() => schema.SchemaDef).Returns(schemaDef);
}
[Fact]
public void Should_normalize_tags()
{
A.CallTo(() => tagService.GetTagIdsAsync(appId, TagGroups.Schemas(schemaId), A<HashSet<string>>.That.Contains("tag1")))
.Returns(new Dictionary<string, string> { ["tag1"] = "normalized1" });
var source = FilterBuilder.Eq("data.tags2.iv", "tag1");
var result = FilterTagTransformer.Transform(source, appId, schema, tagService);
Assert.Equal("data.tags2.iv == normalized1", result.ToString());
}
[Fact]
public void Should_not_fail_when_tags_not_found()
{
A.CallTo(() => tagService.GetTagIdsAsync(appId, TagGroups.Assets, A<HashSet<string>>.That.Contains("tag1")))
.Returns(new Dictionary<string, string>());
var source = FilterBuilder.Eq("data.tags2.iv", "tag1");
var result = FilterTagTransformer.Transform(source, appId, schema, tagService);
Assert.Equal("data.tags2.iv == tag1", result.ToString());
}
[Fact]
public void Should_not_normalize_other_tags_field()
{
var source = FilterBuilder.Eq("data.tags1.iv", "value");
var result = FilterTagTransformer.Transform(source, appId, schema, tagService);
Assert.Equal("data.tags1.iv == value", result.ToString());
A.CallTo(() => tagService.GetTagIdsAsync(appId, A<string>.Ignored, A<HashSet<string>>.Ignored))
.MustNotHaveHappened();
}
[Fact]
public void Should_not_normalize_other_typed_field()
{
var source = FilterBuilder.Eq("data.string.iv", "value");
var result = FilterTagTransformer.Transform(source, appId, schema, tagService);
Assert.Equal("data.string.iv == value", result.ToString());
A.CallTo(() => tagService.GetTagIdsAsync(appId, A<string>.Ignored, A<HashSet<string>>.Ignored))
.MustNotHaveHappened();
}
[Fact]
public void Should_not_normalize_non_data_field()
{
var source = FilterBuilder.Eq("no.data", "value");
var result = FilterTagTransformer.Transform(source, appId, schema, tagService);
Assert.Equal("no.data == value", result.ToString());
A.CallTo(() => tagService.GetTagIdsAsync(appId, A<string>.Ignored, A<HashSet<string>>.Ignored))
.MustNotHaveHappened();
}
}
}
Loading…
Cancel
Save