Browse Source

Generized json.

pull/391/head
Sebastian 7 years ago
parent
commit
c36e943bb1
  1. 4
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs
  2. 4
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs
  3. 6
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs
  4. 2
      src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs
  5. 12
      src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FindExtensions.cs
  6. 4
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs
  7. 4
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  8. 24
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/AdaptionVisitor.cs
  9. 19
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/FilterFactory.cs
  10. 2
      src/Squidex.Domain.Apps.Entities/Assets/AssetQueryService.cs
  11. 10
      src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs
  12. 2
      src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetRepository.cs
  13. 2
      src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs
  14. 4
      src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs
  15. 10
      src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs
  16. 4
      src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs
  17. 4
      src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterBuilder.cs
  18. 60
      src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterVisitor.cs
  19. 4
      src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/LimitExtensions.cs
  20. 2
      src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/SortBuilder.cs
  21. 87
      src/Squidex.Infrastructure/Queries/ClrFilter.cs
  22. 13
      src/Squidex.Infrastructure/Queries/ClrQuery.cs
  23. 140
      src/Squidex.Infrastructure/Queries/ClrValue.cs
  24. 2
      src/Squidex.Infrastructure/Queries/ClrValueType.cs
  25. 67
      src/Squidex.Infrastructure/Queries/CompareFilter.cs
  26. 2
      src/Squidex.Infrastructure/Queries/CompareOperator.cs
  27. 85
      src/Squidex.Infrastructure/Queries/FilterBuilder.cs
  28. 70
      src/Squidex.Infrastructure/Queries/FilterComparison.cs
  29. 45
      src/Squidex.Infrastructure/Queries/FilterJunction.cs
  30. 4
      src/Squidex.Infrastructure/Queries/FilterNode.cs
  31. 8
      src/Squidex.Infrastructure/Queries/FilterNodeVisitor.cs
  32. 149
      src/Squidex.Infrastructure/Queries/FilterValue.cs
  33. 39
      src/Squidex.Infrastructure/Queries/LogicalFilter.cs
  34. 2
      src/Squidex.Infrastructure/Queries/LogicalFilterType.cs
  35. 14
      src/Squidex.Infrastructure/Queries/NegateFilter.cs
  36. 46
      src/Squidex.Infrastructure/Queries/OData/ConstantWithTypeVisitor.cs
  37. 4
      src/Squidex.Infrastructure/Queries/OData/EdmModelExtensions.cs
  38. 2
      src/Squidex.Infrastructure/Queries/OData/FilterBuilder.cs
  39. 46
      src/Squidex.Infrastructure/Queries/OData/FilterVisitor.cs
  40. 4
      src/Squidex.Infrastructure/Queries/OData/LimitExtensions.cs
  41. 2
      src/Squidex.Infrastructure/Queries/OData/SortBuilder.cs
  42. 10
      src/Squidex.Infrastructure/Queries/PascalCasePathConverter.cs
  43. 52
      src/Squidex.Infrastructure/Queries/PropertyPath.cs
  44. 4
      src/Squidex.Infrastructure/Queries/Query.cs
  45. 7
      src/Squidex.Infrastructure/Queries/SortNode.cs
  46. 12
      src/Squidex.Infrastructure/Queries/TransformVisitor.cs
  47. 12
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs
  48. 42
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/MongoDbQueryTests.cs
  49. 6
      tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs
  50. 6
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs
  51. 45
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/MongoDbQueryTests.cs
  52. 10
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/FilterTagTransformerTests.cs
  53. 2
      tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs
  54. 8
      tests/Squidex.Infrastructure.Tests/Queries/PascalCasePathConverterTests.cs

4
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs

@ -14,7 +14,7 @@ using Squidex.Infrastructure.Queries;
namespace Squidex.Domain.Apps.Core.ValidateContent
{
public delegate Task<IReadOnlyList<Guid>> CheckContents(Guid schemaId, FilterNode filter);
public delegate Task<IReadOnlyList<Guid>> CheckContents(Guid schemaId, FilterNode<ClrValue> filter);
public delegate Task<IReadOnlyList<IAssetInfo>> CheckAssets(IEnumerable<Guid> ids);
@ -84,7 +84,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
return new ValidationContext(contentId, schemaId, checkContent, checkAsset, propertyPath.Enqueue(property), IsOptional);
}
public Task<IReadOnlyList<Guid>> GetContentIdsAsync(Guid validatedSchemaId, FilterNode filter)
public Task<IReadOnlyList<Guid>> GetContentIdsAsync(Guid validatedSchemaId, FilterNode<ClrValue> filter)
{
return checkContent(validatedSchemaId, filter);
}

4
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/ReferencesValidator.cs

@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
public sealed class ReferencesValidator : IValidator
{
private static readonly IReadOnlyList<string> Path = new List<string> { "Id" };
private static readonly PropertyPath Path = "Id";
private readonly Guid schemaId;
@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
if (value is ICollection<Guid> contentIds)
{
var filter = new FilterComparison(Path, FilterOperator.In, new FilterValue(contentIds.ToList()));
var filter = ClrFilter.In(Path, contentIds.ToList());
var foundIds = await context.GetContentIdsAsync(schemaId, filter);

6
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs

@ -20,15 +20,15 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
if (value != null && (count == 0 || (count == 2 && context.Path.Last() == InvariantPartitioning.Key)))
{
FilterNode filter = null;
FilterNode<ClrValue> filter = null;
if (value is string s)
{
filter = new FilterComparison(Path(context), FilterOperator.Equals, new FilterValue(s));
filter = ClrFilter.Eq(Path(context), s);
}
else if (value is double d)
{
filter = new FilterComparison(Path(context), FilterOperator.Equals, new FilterValue(d));
filter = ClrFilter.Eq(Path(context), d);
}
if (filter != null)

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

@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
ct);
}
public async Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, Query query)
public async Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, ClrQuery query)
{
using (Profiler.TraceMethod<MongoAssetRepository>("QueryAsyncByQuery"))
{

12
src/Squidex.Domain.Apps.Entities.MongoDb/Assets/Visitors/FindExtensions.cs

@ -20,11 +20,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors
{
private static readonly FilterDefinitionBuilder<MongoAssetEntity> Filter = Builders<MongoAssetEntity>.Filter;
public static Query AdjustToModel(this Query query)
public static ClrQuery AdjustToModel(this ClrQuery query)
{
if (query.Filter != null)
{
query.Filter = PascalCasePathConverter.Transform(query.Filter);
query.Filter = PascalCasePathConverter<ClrValue>.Transform(query.Filter);
}
query.Sort = query.Sort
@ -37,22 +37,22 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets.Visitors
return query;
}
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> AssetSort(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, Query query)
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> AssetSort(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, ClrQuery query)
{
return cursor.Sort(query.BuildSort<MongoAssetEntity>());
}
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> AssetTake(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, Query query)
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> AssetTake(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, ClrQuery query)
{
return cursor.Take(query);
}
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> AssetSkip(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, Query query)
public static IFindFluent<MongoAssetEntity, MongoAssetEntity> AssetSkip(this IFindFluent<MongoAssetEntity, MongoAssetEntity> cursor, ClrQuery query)
{
return cursor.Skip(query);
}
public static FilterDefinition<MongoAssetEntity> BuildFilter(this Query query, Guid appId)
public static FilterDefinition<MongoAssetEntity> BuildFilter(this ClrQuery query, Guid appId)
{
var filters = new List<FilterDefinition<MongoAssetEntity>>
{

4
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs

@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
return "State_Contents";
}
public async Task<IResultList<IContentEntity>> QueryAsync(ISchemaEntity schema, Query query, List<Guid> ids, Status[] status, bool inDraft, bool includeDraft = true)
public async Task<IResultList<IContentEntity>> QueryAsync(ISchemaEntity schema, ClrQuery query, List<Guid> ids, Status[] status, bool inDraft, bool includeDraft = true)
{
try
{
@ -169,7 +169,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
});
}
public async Task<IReadOnlyList<Guid>> QueryIdsAsync(ISchemaEntity schema, FilterNode filterNode)
public async Task<IReadOnlyList<Guid>> QueryIdsAsync(ISchemaEntity schema, FilterNode<ClrValue> filterNode)
{
var filter = filterNode.AdjustToModel(schema.SchemaDef, true).ToFilter(schema.Id);

4
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
return contents.InitializeAsync(ct);
}
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, bool inDraft, Query query, bool includeDraft = true)
public async Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, bool inDraft, ClrQuery query, bool includeDraft = true)
{
Guard.NotNull(app, nameof(app));
Guard.NotNull(schema, nameof(schema));
@ -118,7 +118,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
}
}
public async Task<IReadOnlyList<Guid>> QueryIdsAsync(Guid appId, Guid schemaId, FilterNode filterNode)
public async Task<IReadOnlyList<Guid>> QueryIdsAsync(Guid appId, Guid schemaId, FilterNode<ClrValue> filterNode)
{
using (Profiler.TraceMethod<MongoContentRepository>())
{

24
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/AdaptionVisitor.cs

@ -13,35 +13,35 @@ using Squidex.Infrastructure.Queries;
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
{
internal sealed class AdaptionVisitor : TransformVisitor
internal sealed class AdaptionVisitor : TransformVisitor<ClrValue>
{
private readonly Func<IReadOnlyList<string>, IReadOnlyList<string>> pathConverter;
private readonly Func<PropertyPath, PropertyPath> pathConverter;
public AdaptionVisitor(Func<IReadOnlyList<string>, IReadOnlyList<string>> pathConverter)
public AdaptionVisitor(Func<PropertyPath, PropertyPath> pathConverter)
{
this.pathConverter = pathConverter;
}
public override FilterNode Visit(FilterComparison nodeIn)
public override FilterNode<ClrValue> Visit(CompareFilter<ClrValue> nodeIn)
{
FilterComparison result;
CompareFilter<ClrValue> result;
var value = nodeIn.Rhs.Value;
var value = nodeIn.Value.Value;
if (value is Instant &&
!string.Equals(nodeIn.Lhs[0], "mt", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(nodeIn.Lhs[0], "ct", StringComparison.OrdinalIgnoreCase))
!string.Equals(nodeIn.Path[0], "mt", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(nodeIn.Path[0], "ct", StringComparison.OrdinalIgnoreCase))
{
result = new FilterComparison(pathConverter(nodeIn.Lhs), nodeIn.Operator, new FilterValue(value.ToString()));
result = new CompareFilter<ClrValue>(pathConverter(nodeIn.Path), nodeIn.Operator, value.ToString());
}
else
{
result = new FilterComparison(pathConverter(nodeIn.Lhs), nodeIn.Operator, nodeIn.Rhs);
result = new CompareFilter<ClrValue>(pathConverter(nodeIn.Path), nodeIn.Operator, nodeIn.Value);
}
if (result.Lhs.Count == 1 && result.Lhs[0] == "_id" && result.Rhs.Value is List<Guid> guidList)
if (result.Path.Count == 1 && result.Path[0] == "_id" && result.Value.Value is List<Guid> guidList)
{
result = new FilterComparison(nodeIn.Lhs, nodeIn.Operator, new FilterValue(guidList.Select(x => x.ToString()).ToList()));
result = new CompareFilter<ClrValue>(nodeIn.Path, nodeIn.Operator, guidList.Select(x => x.ToString()).ToList());
}
return result;

19
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/FilterFactory.cs

@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
typeof(MongoContentEntity).GetProperties()
.ToDictionary(x => x.Name, x => x.GetCustomAttribute<BsonElementAttribute>()?.ElementName ?? x.Name, StringComparer.OrdinalIgnoreCase);
public static Query AdjustToModel(this Query query, Schema schema, bool useDraft)
public static ClrQuery AdjustToModel(this ClrQuery query, Schema schema, bool useDraft)
{
var pathConverter = PathConverter(schema, useDraft);
@ -42,14 +42,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
return query;
}
public static FilterNode AdjustToModel(this FilterNode filterNode, Schema schema, bool inDraft)
public static FilterNode<ClrValue> AdjustToModel(this FilterNode<ClrValue> filterNode, Schema schema, bool inDraft)
{
var pathConverter = PathConverter(schema, inDraft);
return filterNode.Accept(new AdaptionVisitor(pathConverter));
}
private static Func<IReadOnlyList<string>, IReadOnlyList<string>> PathConverter(Schema schema, bool inDraft)
private static Func<PropertyPath, PropertyPath> PathConverter(Schema schema, bool inDraft)
{
return propertyNames =>
{
@ -107,17 +107,17 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
};
}
public static IFindFluent<MongoContentEntity, MongoContentEntity> ContentSort(this IFindFluent<MongoContentEntity, MongoContentEntity> cursor, Query query)
public static IFindFluent<MongoContentEntity, MongoContentEntity> ContentSort(this IFindFluent<MongoContentEntity, MongoContentEntity> cursor, ClrQuery query)
{
return cursor.Sort(query.BuildSort<MongoContentEntity>());
}
public static IFindFluent<MongoContentEntity, MongoContentEntity> ContentTake(this IFindFluent<MongoContentEntity, MongoContentEntity> cursor, Query query)
public static IFindFluent<MongoContentEntity, MongoContentEntity> ContentTake(this IFindFluent<MongoContentEntity, MongoContentEntity> cursor, ClrQuery query)
{
return cursor.Take(query);
}
public static IFindFluent<MongoContentEntity, MongoContentEntity> ContentSkip(this IFindFluent<MongoContentEntity, MongoContentEntity> cursor, Query query)
public static IFindFluent<MongoContentEntity, MongoContentEntity> ContentSkip(this IFindFluent<MongoContentEntity, MongoContentEntity> cursor, ClrQuery query)
{
return cursor.Skip(query);
}
@ -142,12 +142,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
return CreateFilter(null, schemaId, ids, status, null);
}
public static FilterDefinition<MongoContentEntity> ToFilter(this Query query, Guid schemaId, ICollection<Guid> ids, Status[] status)
public static FilterDefinition<MongoContentEntity> ToFilter(this ClrQuery query, Guid schemaId, ICollection<Guid> ids, Status[] status)
{
return CreateFilter(null, schemaId, ids, status, query);
}
private static FilterDefinition<MongoContentEntity> CreateFilter(Guid? appId, Guid? schemaId, ICollection<Guid> ids, Status[] status, Query query)
private static FilterDefinition<MongoContentEntity> CreateFilter(Guid? appId, Guid? schemaId, ICollection<Guid> ids, Status[] status,
ClrQuery query)
{
var filters = new List<FilterDefinition<MongoContentEntity>>();
@ -188,7 +189,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
return Filter.And(filters);
}
public static FilterDefinition<MongoContentEntity> ToFilter(this FilterNode filterNode, Guid schemaId)
public static FilterDefinition<MongoContentEntity> ToFilter(this FilterNode<ClrValue> filterNode, Guid schemaId)
{
var filters = new List<FilterDefinition<MongoContentEntity>>
{

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

@ -110,7 +110,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
return assets.SortSet(x => x.Id, ids);
}
private Query ParseQuery(Context context, string query)
private ClrQuery ParseQuery(Context context, string query)
{
try
{

10
src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure.Queries;
namespace Squidex.Domain.Apps.Entities.Assets.Queries
{
public sealed class FilterTagTransformer : TransformVisitor
public sealed class FilterTagTransformer : TransformVisitor<ClrValue>
{
private readonly ITagService tagService;
private readonly Guid appId;
@ -25,22 +25,22 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
this.tagService = tagService;
}
public static FilterNode Transform(FilterNode nodeIn, Guid appId, ITagService tagService)
public static FilterNode<ClrValue> Transform(FilterNode<ClrValue> nodeIn, Guid appId, ITagService tagService)
{
Guard.NotNull(tagService, nameof(tagService));
return nodeIn.Accept(new FilterTagTransformer(appId, tagService));
}
public override FilterNode Visit(FilterComparison nodeIn)
public override FilterNode<ClrValue> Visit(CompareFilter<ClrValue> nodeIn)
{
if (string.Equals(nodeIn.Lhs[0], nameof(IAssetEntity.Tags), StringComparison.OrdinalIgnoreCase) && nodeIn.Rhs.Value is string stringValue)
if (string.Equals(nodeIn.Path[0], nameof(IAssetEntity.Tags), StringComparison.OrdinalIgnoreCase) && nodeIn.Value.Value is string stringValue)
{
var tagNames = Task.Run(() => tagService.GetTagIdsAsync(appId, TagGroups.Assets, HashSet.Of(stringValue))).Result;
if (tagNames.TryGetValue(stringValue, out var normalized))
{
return new FilterComparison(nodeIn.Lhs, nodeIn.Operator, new FilterValue(normalized));
return new CompareFilter<ClrValue>(nodeIn.Path, nodeIn.Operator, normalized);
}
}

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

@ -17,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Repositories
{
Task<IReadOnlyList<IAssetEntity>> QueryByHashAsync(Guid appId, string hash);
Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, Query query);
Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, ClrQuery query);
Task<IResultList<IAssetEntity>> QueryAsync(Guid appId, HashSet<Guid> ids);

2
src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs

@ -122,7 +122,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return await assetRepository.QueryAsync(appEntity.Id, new HashSet<Guid>(assetIds));
}
private async Task<IReadOnlyList<Guid>> QueryContentsAsync(Guid filterSchemaId, FilterNode filterNode)
private async Task<IReadOnlyList<Guid>> QueryContentsAsync(Guid filterSchemaId, FilterNode<ClrValue> filterNode)
{
return await contentRepository.QueryIdsAsync(appEntity.Id, filterSchemaId, filterNode);
}

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

@ -254,7 +254,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
}
}
private Query ParseQuery(Context context, string query, ISchemaEntity schema)
private ClrQuery ParseQuery(Context context, string query, ISchemaEntity schema)
{
using (Profiler.TraceMethod<ContentQueryService>())
{
@ -362,7 +362,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return contentRepository.QueryAsync(context.App, GetStatus(context), new HashSet<Guid>(ids), WithDraft(context));
}
private Task<IResultList<IContentEntity>> QueryCoreAsync(Context context, ISchemaEntity schema, Query query)
private Task<IResultList<IContentEntity>> QueryCoreAsync(Context context, ISchemaEntity schema, ClrQuery query)
{
return contentRepository.QueryAsync(context.App, schema, GetStatus(context), context.IsFrontendClient, query, WithDraft(context));
}

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

@ -16,7 +16,7 @@ using Squidex.Infrastructure.Queries;
namespace Squidex.Domain.Apps.Entities.Contents.Queries
{
public sealed class FilterTagTransformer : TransformVisitor
public sealed class FilterTagTransformer : TransformVisitor<ClrValue>
{
private readonly ITagService tagService;
private readonly ISchemaEntity schema;
@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
this.tagService = tagService;
}
public static FilterNode Transform(FilterNode nodeIn, Guid appId, ISchemaEntity schema, ITagService tagService)
public static FilterNode<ClrValue> Transform(FilterNode<ClrValue> nodeIn, Guid appId, ISchemaEntity schema, ITagService tagService)
{
Guard.NotNull(tagService, nameof(tagService));
Guard.NotNull(schema, nameof(schema));
@ -37,15 +37,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
return nodeIn.Accept(new FilterTagTransformer(appId, schema, tagService));
}
public override FilterNode Visit(FilterComparison nodeIn)
public override FilterNode<ClrValue> Visit(CompareFilter<ClrValue> nodeIn)
{
if (nodeIn.Rhs.Value is string stringValue && IsDataPath(nodeIn.Lhs) && IsTagField(nodeIn.Lhs))
if (nodeIn.Value.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.Lhs, nodeIn.Operator, new FilterValue(normalized));
return new CompareFilter<ClrValue>(nodeIn.Path, nodeIn.Operator, normalized);
}
}

4
src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs

@ -23,9 +23,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Repositories
Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, HashSet<Guid> ids, bool includeDraft);
Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, bool inDraft, Query query, bool includeDraft);
Task<IResultList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, bool inDraft, ClrQuery query, bool includeDraft);
Task<IReadOnlyList<Guid>> QueryIdsAsync(Guid appId, Guid schemaId, FilterNode filterNode);
Task<IReadOnlyList<Guid>> QueryIdsAsync(Guid appId, Guid schemaId, FilterNode<ClrValue> filterNode);
Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Status[] status, Guid id, bool includeDraft);

4
src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterBuilder.cs

@ -12,7 +12,7 @@ namespace Squidex.Infrastructure.MongoDb.Queries
{
public static class FilterBuilder
{
public static (FilterDefinition<T> Filter, bool Last) BuildFilter<T>(this Query query, bool supportsSearch = true)
public static (FilterDefinition<T> Filter, bool Last) BuildFilter<T>(this ClrQuery query, bool supportsSearch = true)
{
if (query.FullText != null)
{
@ -32,7 +32,7 @@ namespace Squidex.Infrastructure.MongoDb.Queries
return (null, false);
}
public static FilterDefinition<T> BuildFilter<T>(this FilterNode filterNode)
public static FilterDefinition<T> BuildFilter<T>(this FilterNode<ClrValue> filterNode)
{
return FilterVisitor<T>.Visit(filterNode);
}

60
src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/FilterVisitor.cs

@ -14,7 +14,7 @@ using Squidex.Infrastructure.Queries;
namespace Squidex.Infrastructure.MongoDb.Queries
{
public sealed class FilterVisitor<T> : FilterNodeVisitor<FilterDefinition<T>>
public sealed class FilterVisitor<T> : FilterNodeVisitor<FilterDefinition<T>, ClrValue>
{
private static readonly FilterDefinitionBuilder<T> Filter = Builders<T>.Filter;
private static readonly FilterVisitor<T> Instance = new FilterVisitor<T>();
@ -23,64 +23,64 @@ namespace Squidex.Infrastructure.MongoDb.Queries
{
}
public static FilterDefinition<T> Visit(FilterNode node)
public static FilterDefinition<T> Visit(FilterNode<ClrValue> node)
{
return node.Accept(Instance);
}
public override FilterDefinition<T> Visit(FilterNegate nodeIn)
public override FilterDefinition<T> Visit(NegateFilter<ClrValue> nodeIn)
{
return Filter.Not(nodeIn.Operand.Accept(this));
return Filter.Not(nodeIn.Filter.Accept(this));
}
public override FilterDefinition<T> Visit(FilterJunction nodeIn)
public override FilterDefinition<T> Visit(LogicalFilter<ClrValue> nodeIn)
{
if (nodeIn.JunctionType == FilterJunctionType.And)
if (nodeIn.Type == LogicalFilterType.And)
{
return Filter.And(nodeIn.Operands.Select(x => x.Accept(this)));
return Filter.And(nodeIn.Filters.Select(x => x.Accept(this)));
}
else
{
return Filter.Or(nodeIn.Operands.Select(x => x.Accept(this)));
return Filter.Or(nodeIn.Filters.Select(x => x.Accept(this)));
}
}
public override FilterDefinition<T> Visit(FilterComparison nodeIn)
public override FilterDefinition<T> Visit(CompareFilter<ClrValue> nodeIn)
{
var propertyName = string.Join(".", nodeIn.Lhs);
var propertyName = nodeIn.Path.ToString();
switch (nodeIn.Operator)
{
case FilterOperator.Empty:
case CompareOperator.Empty:
return Filter.Or(Filter.Exists(propertyName, false), Filter.Eq(propertyName, default(T)), Filter.Eq(propertyName, string.Empty), Filter.Eq(propertyName, new T[0]));
case FilterOperator.StartsWith:
case CompareOperator.StartsWith:
return Filter.Regex(propertyName, BuildRegex(nodeIn, s => "^" + s));
case FilterOperator.Contains:
case CompareOperator.Contains:
return Filter.Regex(propertyName, BuildRegex(nodeIn, s => s));
case FilterOperator.EndsWith:
case CompareOperator.EndsWith:
return Filter.Regex(propertyName, BuildRegex(nodeIn, s => s + "$"));
case FilterOperator.Equals:
return Filter.Eq(propertyName, nodeIn.Rhs.Value);
case FilterOperator.GreaterThan:
return Filter.Gt(propertyName, nodeIn.Rhs.Value);
case FilterOperator.GreaterThanOrEqual:
return Filter.Gte(propertyName, nodeIn.Rhs.Value);
case FilterOperator.LessThan:
return Filter.Lt(propertyName, nodeIn.Rhs.Value);
case FilterOperator.LessThanOrEqual:
return Filter.Lte(propertyName, nodeIn.Rhs.Value);
case FilterOperator.NotEquals:
return Filter.Ne(propertyName, nodeIn.Rhs.Value);
case FilterOperator.In:
return Filter.In(propertyName, ((IList)nodeIn.Rhs.Value).OfType<object>());
case CompareOperator.Equals:
return Filter.Eq(propertyName, nodeIn.Value.Value);
case CompareOperator.GreaterThan:
return Filter.Gt(propertyName, nodeIn.Value.Value);
case CompareOperator.GreaterThanOrEqual:
return Filter.Gte(propertyName, nodeIn.Value.Value);
case CompareOperator.LessThan:
return Filter.Lt(propertyName, nodeIn.Value.Value);
case CompareOperator.LessThanOrEqual:
return Filter.Lte(propertyName, nodeIn.Value.Value);
case CompareOperator.NotEquals:
return Filter.Ne(propertyName, nodeIn.Value.Value);
case CompareOperator.In:
return Filter.In(propertyName, ((IList)nodeIn.Value.Value).OfType<object>());
}
throw new NotSupportedException();
}
private static BsonRegularExpression BuildRegex(FilterComparison node, Func<string, string> formatter)
private static BsonRegularExpression BuildRegex(CompareFilter<ClrValue> node, Func<string, string> formatter)
{
return new BsonRegularExpression(formatter(node.Rhs.Value.ToString()), "i");
return new BsonRegularExpression(formatter(node.Value.Value.ToString()), "i");
}
}
}

4
src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/LimitExtensions.cs

@ -12,7 +12,7 @@ namespace Squidex.Infrastructure.MongoDb.Queries
{
public static class LimitExtensions
{
public static IFindFluent<T, T> Take<T>(this IFindFluent<T, T> cursor, Query query)
public static IFindFluent<T, T> Take<T>(this IFindFluent<T, T> cursor, ClrQuery query)
{
if (query.Take < long.MaxValue)
{
@ -22,7 +22,7 @@ namespace Squidex.Infrastructure.MongoDb.Queries
return cursor;
}
public static IFindFluent<T, T> Skip<T>(this IFindFluent<T, T> cursor, Query query)
public static IFindFluent<T, T> Skip<T>(this IFindFluent<T, T> cursor, ClrQuery query)
{
if (query.Skip > 0)
{

2
src/Squidex.Infrastructure.MongoDb/MongoDb/Queries/SortBuilder.cs

@ -13,7 +13,7 @@ namespace Squidex.Infrastructure.MongoDb.Queries
{
public static class SortBuilder
{
public static SortDefinition<T> BuildSort<T>(this Query query)
public static SortDefinition<T> BuildSort<T>(this ClrQuery query)
{
if (query.Sort.Count > 0)
{

87
src/Squidex.Infrastructure/Queries/ClrFilter.cs

@ -0,0 +1,87 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Queries
{
public static class ClrFilter
{
public static LogicalFilter<ClrValue> And(params FilterNode<ClrValue>[] filters)
{
return new LogicalFilter<ClrValue>(LogicalFilterType.And, filters);
}
public static LogicalFilter<ClrValue> Or(params FilterNode<ClrValue>[] filters)
{
return new LogicalFilter<ClrValue>(LogicalFilterType.Or, filters);
}
public static NegateFilter<ClrValue> Not(FilterNode<ClrValue> filter)
{
return new NegateFilter<ClrValue>(filter);
}
public static CompareFilter<ClrValue> Eq(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.Equals, value);
}
public static CompareFilter<ClrValue> Ne(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.NotEquals, value);
}
public static CompareFilter<ClrValue> Lt(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.LessThan, value);
}
public static CompareFilter<ClrValue> Le(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.LessThanOrEqual, value);
}
public static CompareFilter<ClrValue> Gt(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.GreaterThan, value);
}
public static CompareFilter<ClrValue> Ge(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.GreaterThanOrEqual, value);
}
public static CompareFilter<ClrValue> Contains(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.Contains, value);
}
public static CompareFilter<ClrValue> EndsWith(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.EndsWith, value);
}
public static CompareFilter<ClrValue> StartsWith(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.StartsWith, value);
}
public static CompareFilter<ClrValue> Empty(PropertyPath path)
{
return Binary(path, CompareOperator.Empty, null);
}
public static CompareFilter<ClrValue> In(PropertyPath path, ClrValue value)
{
return Binary(path, CompareOperator.In, value);
}
private static CompareFilter<ClrValue> Binary(PropertyPath path, CompareOperator @operator, ClrValue value)
{
return new CompareFilter<ClrValue>(path, @operator, value ?? ClrValue.Null);
}
}
}

13
src/Squidex.Infrastructure/Queries/ClrQuery.cs

@ -0,0 +1,13 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Queries
{
public sealed class ClrQuery : Query<ClrValue>
{
}
}

140
src/Squidex.Infrastructure/Queries/ClrValue.cs

@ -0,0 +1,140 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using NodaTime;
namespace Squidex.Infrastructure.Queries
{
public sealed class ClrValue
{
public static readonly ClrValue Null = new ClrValue(null, ClrValueType.Null, false);
public object Value { get; }
public ClrValueType ValueType { get; }
public bool IsList { get; }
private ClrValue(object value, ClrValueType valueType, bool isList)
{
Value = value;
ValueType = valueType;
IsList = isList;
}
public static implicit operator ClrValue(Instant value)
{
return new ClrValue(value, ClrValueType.Instant, false);
}
public static implicit operator ClrValue(Guid value)
{
return new ClrValue(value, ClrValueType.Guid, false);
}
public static implicit operator ClrValue(bool value)
{
return new ClrValue(value, ClrValueType.Boolean, false);
}
public static implicit operator ClrValue(float value)
{
return new ClrValue(value, ClrValueType.Single, false);
}
public static implicit operator ClrValue(double value)
{
return new ClrValue(value, ClrValueType.Double, false);
}
public static implicit operator ClrValue(int value)
{
return new ClrValue(value, ClrValueType.Int32, false);
}
public static implicit operator ClrValue(long value)
{
return new ClrValue(value, ClrValueType.Int64, false);
}
public static implicit operator ClrValue(string value)
{
return value != null ? new ClrValue(value, ClrValueType.String, false) : Null;
}
public static implicit operator ClrValue(List<Instant> value)
{
return value != null ? new ClrValue(value, ClrValueType.Instant, true) : Null;
}
public static implicit operator ClrValue(List<Guid> value)
{
return value != null ? new ClrValue(value, ClrValueType.Guid, true) : Null;
}
public static implicit operator ClrValue(List<bool> value)
{
return value != null ? new ClrValue(value, ClrValueType.Boolean, true) : Null;
}
public static implicit operator ClrValue(List<float> value)
{
return value != null ? new ClrValue(value, ClrValueType.Single, true) : Null;
}
public static implicit operator ClrValue(List<double> value)
{
return value != null ? new ClrValue(value, ClrValueType.Double, true) : Null;
}
public static implicit operator ClrValue(List<int> value)
{
return value != null ? new ClrValue(value, ClrValueType.Int32, true) : Null;
}
public static implicit operator ClrValue(List<long> value)
{
return value != null ? new ClrValue(value, ClrValueType.Int64, true) : Null;
}
public static implicit operator ClrValue(List<string> value)
{
return value != null ? new ClrValue(value, ClrValueType.String, true) : Null;
}
public override string ToString()
{
if (Value is IList list)
{
return $"[{string.Join(", ", list.OfType<object>().Select(ToString).ToArray())}]";
}
return ToString(Value);
}
private static string ToString(object value)
{
if (value == null)
{
return "null";
}
if (value is string s)
{
return $"'{s.Replace("'", "\\'")}'";
}
return string.Format(CultureInfo.InvariantCulture, "{0}", value);
}
}
}

2
src/Squidex.Infrastructure/Queries/FilterValueType.cs → src/Squidex.Infrastructure/Queries/ClrValueType.cs

@ -7,7 +7,7 @@
namespace Squidex.Infrastructure.Queries
{
public enum FilterValueType
public enum ClrValueType
{
Boolean,
Guid,

67
src/Squidex.Infrastructure/Queries/CompareFilter.cs

@ -0,0 +1,67 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Infrastructure.Queries
{
public sealed class CompareFilter<TValue> : FilterNode<TValue>
{
public PropertyPath Path { get; }
public CompareOperator Operator { get; }
public TValue Value { get; }
public CompareFilter(PropertyPath path, CompareOperator @operator, TValue value)
{
Guard.NotNull(path, nameof(path));
Guard.NotNull(value, nameof(value));
Guard.Enum(@operator, nameof(@operator));
Path = path;
Operator = @operator;
Value = value;
}
public override T Accept<T>(FilterNodeVisitor<T, TValue> visitor)
{
return visitor.Visit(this);
}
public override string ToString()
{
switch (Operator)
{
case CompareOperator.Contains:
return $"contains({Path}, {Value})";
case CompareOperator.Empty:
return $"empty({Path})";
case CompareOperator.EndsWith:
return $"endsWith({Path}, {Value})";
case CompareOperator.StartsWith:
return $"startsWith({Path}, {Value})";
case CompareOperator.Equals:
return $"{Path} == {Value}";
case CompareOperator.NotEquals:
return $"{Path} != {Value}";
case CompareOperator.GreaterThan:
return $"{Path} > {Value}";
case CompareOperator.GreaterThanOrEqual:
return $"{Path} >= {Value}";
case CompareOperator.LessThan:
return $"{Path} < {Value}";
case CompareOperator.LessThanOrEqual:
return $"{Path} <= {Value}";
case CompareOperator.In:
return $"{Path} in {Value}";
default:
return string.Empty;
}
}
}
}

2
src/Squidex.Infrastructure/Queries/FilterOperator.cs → src/Squidex.Infrastructure/Queries/CompareOperator.cs

@ -7,7 +7,7 @@
namespace Squidex.Infrastructure.Queries
{
public enum FilterOperator
public enum CompareOperator
{
Contains,
Empty,

85
src/Squidex.Infrastructure/Queries/FilterBuilder.cs

@ -1,85 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Linq;
using NodaTime;
namespace Squidex.Infrastructure.Queries
{
public static class FilterBuilder
{
public static FilterJunction And(params FilterNode[] operands)
{
return new FilterJunction(FilterJunctionType.And, operands);
}
public static FilterJunction Or(params FilterNode[] operands)
{
return new FilterJunction(FilterJunctionType.Or, operands);
}
public static FilterComparison Eq(string path, string value)
{
return Binary(path, FilterOperator.Equals, value);
}
public static FilterComparison Eq(string path, bool value)
{
return Binary(path, FilterOperator.Equals, value);
}
public static FilterComparison Eq(string path, long value)
{
return Binary(path, FilterOperator.Equals, value);
}
public static FilterComparison Eq(string path, int value)
{
return Binary(path, FilterOperator.Equals, value);
}
public static FilterComparison Eq(string path, Instant value)
{
return Binary(path, FilterOperator.Equals, value);
}
public static FilterComparison Empty(string path)
{
return new FilterComparison(path.Split('.', '/'), FilterOperator.Empty, FilterValue.Null);
}
public static FilterComparison In(string path, params long[] value)
{
return new FilterComparison(path.Split('.', '/'), FilterOperator.In, new FilterValue(value.ToList()));
}
private static FilterComparison Binary(string path, FilterOperator @operator, string value)
{
return new FilterComparison(path.Split('.', '/'), @operator, new FilterValue(value));
}
private static FilterComparison Binary(string path, FilterOperator @operator, bool value)
{
return new FilterComparison(path.Split('.', '/'), @operator, new FilterValue(value));
}
private static FilterComparison Binary(string path, FilterOperator @operator, long value)
{
return new FilterComparison(path.Split('.', '/'), @operator, new FilterValue(value));
}
private static FilterComparison Binary(string path, FilterOperator @operator, int value)
{
return new FilterComparison(path.Split('.', '/'), @operator, new FilterValue(value));
}
private static FilterComparison Binary(string path, FilterOperator @operator, Instant value)
{
return new FilterComparison(path.Split('.', '/'), @operator, new FilterValue(value));
}
}
}

70
src/Squidex.Infrastructure/Queries/FilterComparison.cs

@ -1,70 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Infrastructure.Queries
{
public sealed class FilterComparison : FilterNode
{
public IReadOnlyList<string> Lhs { get; }
public FilterOperator Operator { get; }
public FilterValue Rhs { get; }
public FilterComparison(IReadOnlyList<string> lhs, FilterOperator @operator, FilterValue rhs)
{
Guard.NotNull(lhs, nameof(lhs));
Guard.NotEmpty(lhs, nameof(lhs));
Guard.Enum(@operator, nameof(@operator));
Lhs = lhs;
Rhs = rhs;
Operator = @operator;
}
public override T Accept<T>(FilterNodeVisitor<T> visitor)
{
return visitor.Visit(this);
}
public override string ToString()
{
var path = string.Join(".", Lhs);
switch (Operator)
{
case FilterOperator.Contains:
return $"contains({path}, {Rhs})";
case FilterOperator.Empty:
return $"empty({path})";
case FilterOperator.EndsWith:
return $"endsWith({path}, {Rhs})";
case FilterOperator.StartsWith:
return $"startsWith({path}, {Rhs})";
case FilterOperator.Equals:
return $"{path} == {Rhs}";
case FilterOperator.NotEquals:
return $"{path} != {Rhs}";
case FilterOperator.GreaterThan:
return $"{path} > {Rhs}";
case FilterOperator.GreaterThanOrEqual:
return $"{path} >= {Rhs}";
case FilterOperator.LessThan:
return $"{path} < {Rhs}";
case FilterOperator.LessThanOrEqual:
return $"{path} <= {Rhs}";
case FilterOperator.In:
return $"{path} in {Rhs}";
default:
return string.Empty;
}
}
}
}

45
src/Squidex.Infrastructure/Queries/FilterJunction.cs

@ -1,45 +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;
namespace Squidex.Infrastructure.Queries
{
public sealed class FilterJunction : FilterNode
{
public IReadOnlyList<FilterNode> Operands { get; }
public FilterJunctionType JunctionType { get; }
public FilterJunction(FilterJunctionType junctionType, IReadOnlyList<FilterNode> operands)
{
Guard.NotNull(operands, nameof(operands));
Guard.GreaterEquals(operands.Count, 2, nameof(operands.Count));
Guard.Enum(junctionType, nameof(junctionType));
Operands = operands;
JunctionType = junctionType;
}
public FilterJunction(FilterJunctionType junctionType, params FilterNode[] operands)
: this(junctionType, operands?.ToList())
{
}
public override T Accept<T>(FilterNodeVisitor<T> visitor)
{
return visitor.Visit(this);
}
public override string ToString()
{
return $"({string.Join(JunctionType == FilterJunctionType.And ? " && " : " || ", Operands)})";
}
}
}

4
src/Squidex.Infrastructure/Queries/FilterNode.cs

@ -7,8 +7,8 @@
namespace Squidex.Infrastructure.Queries
{
public abstract class FilterNode
public abstract class FilterNode<TValue>
{
public abstract T Accept<T>(FilterNodeVisitor<T> visitor);
public abstract T Accept<T>(FilterNodeVisitor<T, TValue> visitor);
}
}

8
src/Squidex.Infrastructure/Queries/FilterNodeVisitor.cs

@ -11,19 +11,19 @@ using System;
namespace Squidex.Infrastructure.Queries
{
public abstract class FilterNodeVisitor<T>
public abstract class FilterNodeVisitor<T, TValue>
{
public virtual T Visit(FilterComparison nodeIn)
public virtual T Visit(CompareFilter<TValue> nodeIn)
{
throw new NotImplementedException();
}
public virtual T Visit(FilterJunction nodeIn)
public virtual T Visit(LogicalFilter<TValue> nodeIn)
{
throw new NotImplementedException();
}
public virtual T Visit(FilterNegate nodeIn)
public virtual T Visit(NegateFilter<TValue> nodeIn)
{
throw new NotImplementedException();
}

149
src/Squidex.Infrastructure/Queries/FilterValue.cs

@ -1,149 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using NodaTime;
namespace Squidex.Infrastructure.Queries
{
public sealed class FilterValue
{
public static readonly FilterValue Null = new FilterValue(null, FilterValueType.Null, false);
public object Value { get; }
public FilterValueType ValueType { get; }
public bool IsList { get; }
public FilterValue(Guid value)
: this(value, FilterValueType.Guid, false)
{
}
public FilterValue(Instant value)
: this(value, FilterValueType.Instant, false)
{
}
public FilterValue(bool value)
: this(value, FilterValueType.Boolean, false)
{
}
public FilterValue(float value)
: this(value, FilterValueType.Single, false)
{
}
public FilterValue(double value)
: this(value, FilterValueType.Double, false)
{
}
public FilterValue(int value)
: this(value, FilterValueType.Int32, false)
{
}
public FilterValue(long value)
: this(value, FilterValueType.Int64, false)
{
}
public FilterValue(string value)
: this(value, FilterValueType.String, false)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<Guid> value)
: this(value, FilterValueType.Guid, true)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<Instant> value)
: this(value, FilterValueType.Instant, true)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<bool> value)
: this(value, FilterValueType.Boolean, true)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<float> value)
: this(value, FilterValueType.Single, true)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<double> value)
: this(value, FilterValueType.Double, true)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<int> value)
: this(value, FilterValueType.Int32, true)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<long> value)
: this(value, FilterValueType.Int64, true)
{
Guard.NotNull(value, nameof(value));
}
public FilterValue(List<string> value)
: this(value, FilterValueType.String, true)
{
Guard.NotNull(value, nameof(value));
}
private FilterValue(object value, FilterValueType valueType, bool isList)
{
Value = value;
ValueType = valueType;
IsList = isList;
}
public override string ToString()
{
if (Value is IList list)
{
return $"[{string.Join(", ", list.OfType<object>().Select(ToString).ToArray())}]";
}
return ToString(Value);
}
private static string ToString(object value)
{
if (value == null)
{
return "null";
}
if (value is string s)
{
return $"'{s.Replace("'", "\\'")}'";
}
return string.Format(CultureInfo.InvariantCulture, "{0}", value);
}
}
}

39
src/Squidex.Infrastructure/Queries/LogicalFilter.cs

@ -0,0 +1,39 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Infrastructure.Queries
{
public sealed class LogicalFilter<TValue> : FilterNode<TValue>
{
public IReadOnlyList<FilterNode<TValue>> Filters { get; }
public LogicalFilterType Type { get; }
public LogicalFilter(LogicalFilterType type, IReadOnlyList<FilterNode<TValue>> filters)
{
Guard.NotNull(filters, nameof(filters));
Guard.GreaterEquals(filters.Count, 2, nameof(filters.Count));
Guard.Enum(type, nameof(type));
Filters = filters;
Type = type;
}
public override T Accept<T>(FilterNodeVisitor<T, TValue> visitor)
{
return visitor.Visit(this);
}
public override string ToString()
{
return $"({string.Join(Type == LogicalFilterType.And ? " && " : " || ", Filters)})";
}
}
}

2
src/Squidex.Infrastructure/Queries/FilterJunctionType.cs → src/Squidex.Infrastructure/Queries/LogicalFilterType.cs

@ -7,7 +7,7 @@
namespace Squidex.Infrastructure.Queries
{
public enum FilterJunctionType
public enum LogicalFilterType
{
And,
Or

14
src/Squidex.Infrastructure/Queries/FilterNegate.cs → src/Squidex.Infrastructure/Queries/NegateFilter.cs

@ -7,25 +7,25 @@
namespace Squidex.Infrastructure.Queries
{
public sealed class FilterNegate : FilterNode
public sealed class NegateFilter<TValue> : FilterNode<TValue>
{
public FilterNode Operand { get; }
public FilterNode<TValue> Filter { get; }
public FilterNegate(FilterNode operand)
public NegateFilter(FilterNode<TValue> filter)
{
Guard.NotNull(operand, nameof(operand));
Guard.NotNull(filter, nameof(filter));
Operand = operand;
Filter = filter;
}
public override T Accept<T>(FilterNodeVisitor<T> visitor)
public override T Accept<T>(FilterNodeVisitor<T, TValue> visitor)
{
return visitor.Visit(this);
}
public override string ToString()
{
return $"!({Operand})";
return $"!({Filter})";
}
}
}

46
src/Squidex.Infrastructure/Queries/OData/ConstantWithTypeVisitor.cs

@ -15,7 +15,7 @@ using NodaTime.Text;
namespace Squidex.Infrastructure.Queries.OData
{
public sealed class ConstantWithTypeVisitor : QueryNodeVisitor<FilterValue>
public sealed class ConstantWithTypeVisitor : QueryNodeVisitor<ClrValue>
{
private static readonly IEdmPrimitiveType BooleanType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.Boolean);
private static readonly IEdmPrimitiveType DateTimeType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.DateTimeOffset);
@ -32,117 +32,117 @@ namespace Squidex.Infrastructure.Queries.OData
{
}
public static FilterValue Visit(QueryNode node)
public static ClrValue Visit(QueryNode node)
{
return node.Accept(Instance);
}
public override FilterValue Visit(ConvertNode nodeIn)
public override ClrValue Visit(ConvertNode nodeIn)
{
if (nodeIn.TypeReference.Definition == BooleanType)
{
var value = ConstantVisitor.Visit(nodeIn.Source);
return new FilterValue(bool.Parse(value.ToString()));
return bool.Parse(value.ToString());
}
if (nodeIn.TypeReference.Definition == GuidType)
{
var value = ConstantVisitor.Visit(nodeIn.Source);
return new FilterValue(Guid.Parse(value.ToString()));
return Guid.Parse(value.ToString());
}
if (nodeIn.TypeReference.Definition == DateTimeType)
{
var value = ConstantVisitor.Visit(nodeIn.Source);
return new FilterValue(ParseInstant(value));
return ParseInstant(value);
}
if (ConstantVisitor.Visit(nodeIn.Source) == null)
{
return FilterValue.Null;
return ClrValue.Null;
}
throw new NotSupportedException();
}
public override FilterValue Visit(CollectionConstantNode nodeIn)
public override ClrValue Visit(CollectionConstantNode nodeIn)
{
if (nodeIn.ItemType.Definition == DateTimeType)
{
return new FilterValue(nodeIn.Collection.Select(x => ParseInstant(x.Value)).ToList());
return nodeIn.Collection.Select(x => ParseInstant(x.Value)).ToList();
}
if (nodeIn.ItemType.Definition == GuidType)
{
return new FilterValue(nodeIn.Collection.Select(x => (Guid)x.Value).ToList());
return nodeIn.Collection.Select(x => (Guid)x.Value).ToList();
}
if (nodeIn.ItemType.Definition == BooleanType)
{
return new FilterValue(nodeIn.Collection.Select(x => (bool)x.Value).ToList());
return nodeIn.Collection.Select(x => (bool)x.Value).ToList();
}
if (nodeIn.ItemType.Definition == SingleType)
{
return new FilterValue(nodeIn.Collection.Select(x => (float)x.Value).ToList());
return nodeIn.Collection.Select(x => (float)x.Value).ToList();
}
if (nodeIn.ItemType.Definition == DoubleType)
{
return new FilterValue(nodeIn.Collection.Select(x => (double)x.Value).ToList());
return nodeIn.Collection.Select(x => (double)x.Value).ToList();
}
if (nodeIn.ItemType.Definition == Int32Type)
{
return new FilterValue(nodeIn.Collection.Select(x => (int)x.Value).ToList());
return nodeIn.Collection.Select(x => (int)x.Value).ToList();
}
if (nodeIn.ItemType.Definition == Int64Type)
{
return new FilterValue(nodeIn.Collection.Select(x => (long)x.Value).ToList());
return nodeIn.Collection.Select(x => (long)x.Value).ToList();
}
if (nodeIn.ItemType.Definition == StringType)
{
return new FilterValue(nodeIn.Collection.Select(x => (string)x.Value).ToList());
return nodeIn.Collection.Select(x => (string)x.Value).ToList();
}
throw new NotSupportedException();
}
public override FilterValue Visit(ConstantNode nodeIn)
public override ClrValue Visit(ConstantNode nodeIn)
{
if (nodeIn.TypeReference.Definition == BooleanType)
{
return new FilterValue((bool)nodeIn.Value);
return (bool)nodeIn.Value;
}
if (nodeIn.TypeReference.Definition == SingleType)
{
return new FilterValue((float)nodeIn.Value);
return (float)nodeIn.Value;
}
if (nodeIn.TypeReference.Definition == DoubleType)
{
return new FilterValue((double)nodeIn.Value);
return (double)nodeIn.Value;
}
if (nodeIn.TypeReference.Definition == Int32Type)
{
return new FilterValue((int)nodeIn.Value);
return (int)nodeIn.Value;
}
if (nodeIn.TypeReference.Definition == Int64Type)
{
return new FilterValue((long)nodeIn.Value);
return (long)nodeIn.Value;
}
if (nodeIn.TypeReference.Definition == StringType)
{
return new FilterValue((string)nodeIn.Value);
return (string)nodeIn.Value;
}
throw new NotSupportedException();

4
src/Squidex.Infrastructure/Queries/OData/EdmModelExtensions.cs

@ -43,9 +43,9 @@ namespace Squidex.Infrastructure.Queries.OData
return parser;
}
public static Query ToQuery(this ODataUriParser parser)
public static ClrQuery ToQuery(this ODataUriParser parser)
{
var query = new Query();
var query = new ClrQuery();
if (parser != null)
{

2
src/Squidex.Infrastructure/Queries/OData/FilterBuilder.cs

@ -12,7 +12,7 @@ namespace Squidex.Infrastructure.Queries.OData
{
public static class FilterBuilder
{
public static void ParseFilter(this ODataUriParser query, Query result)
public static void ParseFilter(this ODataUriParser query, ClrQuery result)
{
SearchClause search;
try

46
src/Squidex.Infrastructure/Queries/OData/FilterVisitor.cs

@ -11,7 +11,7 @@ using Microsoft.OData.UriParser;
namespace Squidex.Infrastructure.Queries.OData
{
public sealed class FilterVisitor : QueryNodeVisitor<FilterNode>
public sealed class FilterVisitor : QueryNodeVisitor<FilterNode<ClrValue>>
{
private static readonly FilterVisitor Instance = new FilterVisitor();
@ -19,40 +19,40 @@ namespace Squidex.Infrastructure.Queries.OData
{
}
public static FilterNode Visit(QueryNode node)
public static FilterNode<ClrValue> Visit(QueryNode node)
{
return node.Accept(Instance);
}
public override FilterNode Visit(ConvertNode nodeIn)
public override FilterNode<ClrValue> Visit(ConvertNode nodeIn)
{
return nodeIn.Source.Accept(this);
}
public override FilterNode Visit(UnaryOperatorNode nodeIn)
public override FilterNode<ClrValue> Visit(UnaryOperatorNode nodeIn)
{
if (nodeIn.OperatorKind == UnaryOperatorKind.Not)
{
return new FilterNegate(nodeIn.Operand.Accept(this));
return ClrFilter.Not(nodeIn.Operand.Accept(this));
}
throw new NotSupportedException();
}
public override FilterNode Visit(InNode nodeIn)
public override FilterNode<ClrValue> Visit(InNode nodeIn)
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.In, value);
return ClrFilter.In(PropertyPathVisitor.Visit(nodeIn.Left), value);
}
public override FilterNode Visit(SingleValueFunctionCallNode nodeIn)
public override FilterNode<ClrValue> Visit(SingleValueFunctionCallNode nodeIn)
{
var fieldNode = nodeIn.Parameters.ElementAt(0);
if (string.Equals(nodeIn.Name, "empty", StringComparison.OrdinalIgnoreCase))
{
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.Empty, FilterValue.Null);
return ClrFilter.Empty(PropertyPathVisitor.Visit(fieldNode));
}
var valueNode = nodeIn.Parameters.ElementAt(1);
@ -61,36 +61,36 @@ namespace Squidex.Infrastructure.Queries.OData
{
var value = ConstantWithTypeVisitor.Visit(valueNode);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.EndsWith, value);
return ClrFilter.EndsWith(PropertyPathVisitor.Visit(fieldNode), value);
}
if (string.Equals(nodeIn.Name, "startswith", StringComparison.OrdinalIgnoreCase))
{
var value = ConstantWithTypeVisitor.Visit(valueNode);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.StartsWith, value);
return ClrFilter.StartsWith(PropertyPathVisitor.Visit(fieldNode), value);
}
if (string.Equals(nodeIn.Name, "contains", StringComparison.OrdinalIgnoreCase))
{
var value = ConstantWithTypeVisitor.Visit(valueNode);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.Contains, value);
return ClrFilter.Contains(PropertyPathVisitor.Visit(fieldNode), value);
}
throw new NotSupportedException();
}
public override FilterNode Visit(BinaryOperatorNode nodeIn)
public override FilterNode<ClrValue> Visit(BinaryOperatorNode nodeIn)
{
if (nodeIn.OperatorKind == BinaryOperatorKind.And)
{
return new FilterJunction(FilterJunctionType.And, nodeIn.Left.Accept(this), nodeIn.Right.Accept(this));
return ClrFilter.And(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this));
}
if (nodeIn.OperatorKind == BinaryOperatorKind.Or)
{
return new FilterJunction(FilterJunctionType.Or, nodeIn.Left.Accept(this), nodeIn.Right.Accept(this));
return ClrFilter.Or(nodeIn.Left.Accept(this), nodeIn.Right.Accept(this));
}
if (nodeIn.Left is SingleValueFunctionCallNode functionNode)
@ -99,12 +99,12 @@ namespace Squidex.Infrastructure.Queries.OData
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
if (value.ValueType == FilterValueType.Boolean && value.Value is bool booleanRight)
if (value.ValueType == ClrValueType.Boolean && value.Value is bool booleanRight)
{
if ((nodeIn.OperatorKind == BinaryOperatorKind.Equal && !booleanRight) ||
(nodeIn.OperatorKind == BinaryOperatorKind.NotEqual && booleanRight))
{
regexFilter = new FilterNegate(regexFilter);
regexFilter = ClrFilter.Not(regexFilter);
}
return regexFilter;
@ -116,42 +116,42 @@ namespace Squidex.Infrastructure.Queries.OData
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.NotEquals, value);
return ClrFilter.Ne(PropertyPathVisitor.Visit(nodeIn.Left), value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.Equal)
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.Equals, value);
return ClrFilter.Eq(PropertyPathVisitor.Visit(nodeIn.Left), value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.LessThan)
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.LessThan, value);
return ClrFilter.Lt(PropertyPathVisitor.Visit(nodeIn.Left), value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.LessThanOrEqual)
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.LessThanOrEqual, value);
return ClrFilter.Le(PropertyPathVisitor.Visit(nodeIn.Left), value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThan)
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.GreaterThan, value);
return ClrFilter.Gt(PropertyPathVisitor.Visit(nodeIn.Left), value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThanOrEqual)
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.GreaterThanOrEqual, value);
return ClrFilter.Ge(PropertyPathVisitor.Visit(nodeIn.Left), value);
}
}

4
src/Squidex.Infrastructure/Queries/OData/LimitExtensions.cs

@ -11,7 +11,7 @@ namespace Squidex.Infrastructure.Queries.OData
{
public static class LimitExtensions
{
public static void ParseTake(this ODataUriParser query, Query result)
public static void ParseTake(this ODataUriParser query, ClrQuery result)
{
var top = query.ParseTop();
@ -21,7 +21,7 @@ namespace Squidex.Infrastructure.Queries.OData
}
}
public static void ParseSkip(this ODataUriParser query, Query result)
public static void ParseSkip(this ODataUriParser query, ClrQuery result)
{
var skip = query.ParseSkip();

2
src/Squidex.Infrastructure/Queries/OData/SortBuilder.cs

@ -11,7 +11,7 @@ namespace Squidex.Infrastructure.Queries.OData
{
public static class SortBuilder
{
public static void ParseSort(this ODataUriParser query, Query result)
public static void ParseSort(this ODataUriParser query, ClrQuery result)
{
var orderBy = query.ParseOrderBy();

10
src/Squidex.Infrastructure/Queries/PascalCasePathConverter.cs

@ -9,22 +9,22 @@ using System.Linq;
namespace Squidex.Infrastructure.Queries
{
public sealed class PascalCasePathConverter : TransformVisitor
public sealed class PascalCasePathConverter<TValue> : TransformVisitor<TValue>
{
private static readonly PascalCasePathConverter Instance = new PascalCasePathConverter();
private static readonly PascalCasePathConverter<TValue> Instance = new PascalCasePathConverter<TValue>();
private PascalCasePathConverter()
{
}
public static FilterNode Transform(FilterNode node)
public static FilterNode<TValue> Transform(FilterNode<TValue> node)
{
return node.Accept(Instance);
}
public override FilterNode Visit(FilterComparison nodeIn)
public override FilterNode<TValue> Visit(CompareFilter<TValue> nodeIn)
{
return new FilterComparison(nodeIn.Lhs.Select(x => x.ToPascalCase()).ToList(), nodeIn.Operator, nodeIn.Rhs);
return new CompareFilter<TValue>(nodeIn.Path.Select(x => x.ToPascalCase()).ToList(), nodeIn.Operator, nodeIn.Value);
}
}
}

52
src/Squidex.Infrastructure/Queries/PropertyPath.cs

@ -0,0 +1,52 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
namespace Squidex.Infrastructure.Queries
{
public sealed class PropertyPath : ReadOnlyCollection<string>
{
public PropertyPath(IList<string> items)
: base(items)
{
if (items.Count == 0)
{
throw new ArgumentException("Path cannot be empty.", nameof(items));
}
}
public static implicit operator PropertyPath(string path)
{
return new PropertyPath(path?.Split('.', '/')?.ToList());
}
public static implicit operator PropertyPath(string[] path)
{
return new PropertyPath(path?.ToList());
}
public static implicit operator PropertyPath(List<string> path)
{
return new PropertyPath(path);
}
public static implicit operator PropertyPath(ImmutableList<string> path)
{
return new PropertyPath(path);
}
public override string ToString()
{
return string.Join(".", this);
}
}
}

4
src/Squidex.Infrastructure/Queries/Query.cs

@ -9,9 +9,9 @@ using System.Collections.Generic;
namespace Squidex.Infrastructure.Queries
{
public sealed class Query
public class Query<TValue>
{
public FilterNode Filter { get; set; }
public FilterNode<TValue> Filter { get; set; }
public string FullText { get; set; }

7
src/Squidex.Infrastructure/Queries/SortNode.cs

@ -5,20 +5,17 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Infrastructure.Queries
{
public sealed class SortNode
{
public IReadOnlyList<string> Path { get; }
public PropertyPath Path { get; }
public SortOrder SortOrder { get; set; }
public SortNode(IReadOnlyList<string> path, SortOrder sortOrder)
public SortNode(PropertyPath path, SortOrder sortOrder)
{
Guard.NotNull(path, nameof(path));
Guard.NotEmpty(path, nameof(path));
Guard.Enum(sortOrder, nameof(sortOrder));
Path = path;

12
src/Squidex.Infrastructure/Queries/TransformVisitor.cs

@ -9,21 +9,21 @@ using System.Linq;
namespace Squidex.Infrastructure.Queries
{
public abstract class TransformVisitor : FilterNodeVisitor<FilterNode>
public abstract class TransformVisitor<TValue> : FilterNodeVisitor<FilterNode<TValue>, TValue>
{
public override FilterNode Visit(FilterComparison nodeIn)
public override FilterNode<TValue> Visit(CompareFilter<TValue> nodeIn)
{
return nodeIn;
}
public override FilterNode Visit(FilterJunction nodeIn)
public override FilterNode<TValue> Visit(LogicalFilter<TValue> nodeIn)
{
return new FilterJunction(nodeIn.JunctionType, nodeIn.Operands.Select(x => x.Accept(this)).ToList());
return new LogicalFilter<TValue>(nodeIn.Type, nodeIn.Filters.Select(x => x.Accept(this)).ToList());
}
public override FilterNode Visit(FilterNegate nodeIn)
public override FilterNode<TValue> Visit(NegateFilter<TValue> nodeIn)
{
return new FilterNegate(nodeIn.Operand.Accept(this));
return new NegateFilter<TValue>(nodeIn.Filter.Accept(this));
}
}
}

12
tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetQueryServiceTests.cs

@ -115,7 +115,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
var enriched1 = new AssetEntity();
var enriched2 = new AssetEntity();
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.Ignored))
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<ClrQuery>.Ignored))
.Returns(ResultList.CreateFrom(8, found1, found2));
A.CallTo(() => assetEnricher.EnrichAsync(A<IEnumerable<IAssetEntity>>.That.IsSameSequenceAs(found1, found2)))
@ -135,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.QueryAsync(requestContext, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("FullText: 'Hello World'; Take: 100; Sort: fileName Ascending")))
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<ClrQuery>.That.Is("FullText: 'Hello World'; Take: 100; Sort: fileName Ascending")))
.MustHaveHappened();
}
@ -146,7 +146,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.QueryAsync(requestContext, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("Filter: fileName == 'ABC'; Take: 200; Sort: lastModified Descending")))
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<ClrQuery>.That.Is("Filter: fileName == 'ABC'; Take: 200; Sort: lastModified Descending")))
.MustHaveHappened();
}
@ -157,7 +157,8 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.QueryAsync(requestContext, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("Take: 30; Sort: lastModified Descending")))
A.CallTo(() => assetRepository.QueryAsync(appId.Id,
A<ClrQuery>.That.Is("Take: 30; Sort: lastModified Descending")))
.MustHaveHappened();
}
@ -168,7 +169,8 @@ namespace Squidex.Domain.Apps.Entities.Assets
await sut.QueryAsync(requestContext, query);
A.CallTo(() => assetRepository.QueryAsync(appId.Id, A<Query>.That.Is("Skip: 20; Take: 200; Sort: lastModified Descending")))
A.CallTo(() => assetRepository.QueryAsync(appId.Id,
A<ClrQuery>.That.Is("Skip: 20; Take: 200; Sort: lastModified Descending")))
.MustHaveHappened();
}
}

42
tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/MongoDbQueryTests.cs

@ -17,7 +17,7 @@ using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.MongoDb.Queries;
using Squidex.Infrastructure.Queries;
using Xunit;
using FilterBuilder = Squidex.Infrastructure.Queries.FilterBuilder;
using ClrFilter = Squidex.Infrastructure.Queries.ClrFilter;
using SortBuilder = Squidex.Infrastructure.Queries.SortBuilder;
namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
@ -35,13 +35,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_throw_exception_for_full_text_search()
{
Assert.Throws<ValidationException>(() => Q(new Query { FullText = "Full Text" }));
Assert.Throws<ValidationException>(() => Q(new ClrQuery { FullText = "Full Text" }));
}
[Fact]
public void Should_make_query_with_lastModified()
{
var i = F(FilterBuilder.Eq("lastModified", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var i = F(ClrFilter.Eq("lastModified", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var o = C("{ 'LastModified' : ISODate('1988-01-19T12:00:00Z') }");
Assert.Equal(o, i);
@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_lastModifiedBy()
{
var i = F(FilterBuilder.Eq("lastModifiedBy", "Me"));
var i = F(ClrFilter.Eq("lastModifiedBy", "Me"));
var o = C("{ 'LastModifiedBy' : 'Me' }");
Assert.Equal(o, i);
@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_created()
{
var i = F(FilterBuilder.Eq("created", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var i = F(ClrFilter.Eq("created", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var o = C("{ 'Created' : ISODate('1988-01-19T12:00:00Z') }");
Assert.Equal(o, i);
@ -68,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_createdBy()
{
var i = F(FilterBuilder.Eq("createdBy", "Me"));
var i = F(ClrFilter.Eq("createdBy", "Me"));
var o = C("{ 'CreatedBy' : 'Me' }");
Assert.Equal(o, i);
@ -77,7 +77,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_version()
{
var i = F(FilterBuilder.Eq("version", 0));
var i = F(ClrFilter.Eq("version", 0));
var o = C("{ 'Version' : NumberLong(0) }");
Assert.Equal(o, i);
@ -86,7 +86,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_fileVersion()
{
var i = F(FilterBuilder.Eq("fileVersion", 2));
var i = F(ClrFilter.Eq("fileVersion", 2));
var o = C("{ 'FileVersion' : NumberLong(2) }");
Assert.Equal(o, i);
@ -95,7 +95,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_tags()
{
var i = F(FilterBuilder.Eq("tags", "tag1"));
var i = F(ClrFilter.Eq("tags", "tag1"));
var o = C("{ 'Tags' : 'tag1' }");
Assert.Equal(o, i);
@ -104,7 +104,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_fileName()
{
var i = F(FilterBuilder.Eq("fileName", "Logo.png"));
var i = F(ClrFilter.Eq("fileName", "Logo.png"));
var o = C("{ 'FileName' : 'Logo.png' }");
Assert.Equal(o, i);
@ -113,7 +113,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_isImage()
{
var i = F(FilterBuilder.Eq("isImage", true));
var i = F(ClrFilter.Eq("isImage", true));
var o = C("{ 'IsImage' : true }");
Assert.Equal(o, i);
@ -122,7 +122,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_mimeType()
{
var i = F(FilterBuilder.Eq("mimeType", "text/json"));
var i = F(ClrFilter.Eq("mimeType", "text/json"));
var o = C("{ 'MimeType' : 'text/json' }");
Assert.Equal(o, i);
@ -131,7 +131,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_fileSize()
{
var i = F(FilterBuilder.Eq("fileSize", 1024));
var i = F(ClrFilter.Eq("fileSize", 1024));
var o = C("{ 'FileSize' : NumberLong(1024) }");
Assert.Equal(o, i);
@ -140,7 +140,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_pixelHeight()
{
var i = F(FilterBuilder.Eq("pixelHeight", 600));
var i = F(ClrFilter.Eq("pixelHeight", 600));
var o = C("{ 'PixelHeight' : 600 }");
Assert.Equal(o, i);
@ -149,7 +149,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_query_with_pixelWidth()
{
var i = F(FilterBuilder.Eq("pixelWidth", 800));
var i = F(ClrFilter.Eq("pixelWidth", 800));
var o = C("{ 'PixelWidth' : 800 }");
Assert.Equal(o, i);
@ -176,7 +176,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_take_statement()
{
var query = new Query { Take = 3 };
var query = new ClrQuery { Take = 3 };
var cursor = A.Fake<IFindFluent<MongoAssetEntity, MongoAssetEntity>>();
cursor.AssetTake(query.AdjustToModel());
@ -188,7 +188,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
[Fact]
public void Should_make_skip_statement()
{
var query = new Query { Skip = 3 };
var query = new ClrQuery { Skip = 3 };
var cursor = A.Fake<IFindFluent<MongoAssetEntity, MongoAssetEntity>>();
cursor.AssetSkip(query.AdjustToModel());
@ -202,9 +202,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
return value.Replace('\'', '"');
}
private static string F(FilterNode filter)
private static string F(FilterNode<ClrValue> filter)
{
return Q(new Query { Filter = filter });
return Q(new ClrQuery { Filter = filter });
}
private static string S(params SortNode[] sorts)
@ -219,12 +219,12 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb
i = sortDefinition.Render(Serializer, Registry).ToString();
});
cursor.AssetSort(new Query { Sort = sorts.ToList() }.AdjustToModel());
cursor.AssetSort(new ClrQuery { Sort = sorts.ToList() }.AdjustToModel());
return i;
}
private static string Q(Query query)
private static string Q(ClrQuery query)
{
var rendered =
query.AdjustToModel().BuildFilter<MongoAssetEntity>(false).Filter

6
tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/FilterTagTransformerTests.cs

@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
A.CallTo(() => tagService.GetTagIdsAsync(appId, TagGroups.Assets, A<HashSet<string>>.That.Contains("name1")))
.Returns(new Dictionary<string, string> { ["name1"] = "id1" });
var source = FilterBuilder.Eq("tags", "name1");
var source = ClrFilter.Eq("tags", "name1");
var result = FilterTagTransformer.Transform(source, appId, tagService);
Assert.Equal("tags == 'id1'", result.ToString());
@ -37,7 +37,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
A.CallTo(() => tagService.GetTagIdsAsync(appId, TagGroups.Assets, A<HashSet<string>>.That.Contains("name1")))
.Returns(new Dictionary<string, string>());
var source = FilterBuilder.Eq("tags", "name1");
var source = ClrFilter.Eq("tags", "name1");
var result = FilterTagTransformer.Transform(source, appId, tagService);
Assert.Equal("tags == 'name1'", result.ToString());
@ -46,7 +46,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
[Fact]
public void Should_not_normalize_other_field()
{
var source = FilterBuilder.Eq("other", "value");
var source = ClrFilter.Eq("other", "value");
var result = FilterTagTransformer.Transform(source, appId, tagService);
Assert.Equal("other == 'value'", result.ToString());

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

@ -149,7 +149,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
await sut.QueryAsync(requestContext, schemaId.Name, query);
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(Status.Published), false,
A<Query>.That.Is("Take: 30; Sort: lastModified Descending"), false))
A<ClrQuery>.That.Is("Take: 30; Sort: lastModified Descending"), false))
.MustHaveHappened();
}
@ -166,7 +166,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
await sut.QueryAsync(requestContext, schemaId.Name, query);
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(status), false,
A<Query>.That.Is("Skip: 20; Take: 200; Sort: lastModified Descending"), false))
A<ClrQuery>.That.Is("Skip: 20; Take: 200; Sort: lastModified Descending"), false))
.MustHaveHappened();
}
@ -482,7 +482,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
private void SetupContents(Status[] status, int count, int total, IContentEntity content, bool inDraft, bool includeDraft)
{
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(status), inDraft, A<Query>.Ignored, includeDraft))
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.Is(status), inDraft, A<ClrQuery>.Ignored, includeDraft))
.Returns(ResultList.Create(total, Enumerable.Repeat(content, count)));
}

45
tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/MongoDbQueryTests.cs

@ -6,6 +6,7 @@
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using FakeItEasy;
using MongoDB.Bson.Serialization;
@ -23,7 +24,7 @@ using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.MongoDb.Queries;
using Squidex.Infrastructure.Queries;
using Xunit;
using FilterBuilder = Squidex.Infrastructure.Queries.FilterBuilder;
using ClrFilter = Squidex.Infrastructure.Queries.ClrFilter;
using SortBuilder = Squidex.Infrastructure.Queries.SortBuilder;
namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
@ -78,13 +79,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_throw_exception_for_invalid_field()
{
Assert.Throws<NotSupportedException>(() => F(FilterBuilder.Eq("data/invalid/iv", "Me")));
Assert.Throws<NotSupportedException>(() => F(ClrFilter.Eq("data/invalid/iv", "Me")));
}
[Fact]
public void Should_make_query_with_lastModified()
{
var i = F(FilterBuilder.Eq("lastModified", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var i = F(ClrFilter.Eq("lastModified", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var o = C("{ 'mt' : '1988-01-19T12:00:00Z' }");
Assert.Equal(o, i);
@ -93,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_lastModifiedBy()
{
var i = F(FilterBuilder.Eq("lastModifiedBy", "Me"));
var i = F(ClrFilter.Eq("lastModifiedBy", "Me"));
var o = C("{ 'mb' : 'Me' }");
Assert.Equal(o, i);
@ -102,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_created()
{
var i = F(FilterBuilder.Eq("created", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var i = F(ClrFilter.Eq("created", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var o = C("{ 'ct' : '1988-01-19T12:00:00Z' }");
Assert.Equal(o, i);
@ -111,7 +112,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_createdBy()
{
var i = F(FilterBuilder.Eq("createdBy", "Me"));
var i = F(ClrFilter.Eq("createdBy", "Me"));
var o = C("{ 'cb' : 'Me' }");
Assert.Equal(o, i);
@ -120,7 +121,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_version()
{
var i = F(FilterBuilder.Eq("version", 0L));
var i = F(ClrFilter.Eq("version", 0L));
var o = C("{ 'vs' : NumberLong(0) }");
Assert.Equal(o, i);
@ -129,7 +130,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_version_and_list()
{
var i = F(FilterBuilder.In("version", 0L, 2L, 5L));
var i = F(ClrFilter.In("version", new List<long> { 0L, 2L, 5L }));
var o = C("{ 'vs' : { '$in' : [NumberLong(0), NumberLong(2), NumberLong(5)] } }");
Assert.Equal(o, i);
@ -138,7 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_from_draft()
{
var i = F(FilterBuilder.Eq("data/dashed_field/iv", "Value"), true);
var i = F(ClrFilter.Eq("data/dashed_field/iv", "Value"), true);
var o = C("{ 'dd.8.iv' : 'Value' }");
Assert.Equal(o, i);
@ -147,7 +148,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_empty_test()
{
var i = F(FilterBuilder.Empty("data/firstName/iv"), true);
var i = F(ClrFilter.Empty("data/firstName/iv"), true);
var o = C("{ '$or' : [{ 'dd.1.iv' : { '$exists' : false } }, { 'dd.1.iv' : null }, { 'dd.1.iv' : '' }, { 'dd.1.iv' : [] }] }");
Assert.Equal(o, i);
@ -156,7 +157,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_datetime_data()
{
var i = F(FilterBuilder.Eq("data/birthday/iv", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var i = F(ClrFilter.Eq("data/birthday/iv", InstantPattern.General.Parse("1988-01-19T12:00:00Z").Value));
var o = C("{ 'do.5.iv' : '1988-01-19T12:00:00Z' }");
Assert.Equal(o, i);
@ -165,7 +166,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_underscore_field()
{
var i = F(FilterBuilder.Eq("data/dashed_field/iv", "Value"));
var i = F(ClrFilter.Eq("data/dashed_field/iv", "Value"));
var o = C("{ 'do.8.iv' : 'Value' }");
Assert.Equal(o, i);
@ -174,7 +175,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_references_equals()
{
var i = F(FilterBuilder.Eq("data/friends/iv", "guid"));
var i = F(ClrFilter.Eq("data/friends/iv", "guid"));
var o = C("{ 'do.7.iv' : 'guid' }");
Assert.Equal(o, i);
@ -183,7 +184,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_array_field()
{
var i = F(FilterBuilder.Eq("data/hobbies/iv/name", "PC"));
var i = F(ClrFilter.Eq("data/hobbies/iv/name", "PC"));
var o = C("{ 'do.9.iv.91' : 'PC' }");
Assert.Equal(o, i);
@ -192,7 +193,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_assets_equals()
{
var i = F(FilterBuilder.Eq("data/pictures/iv", "guid"));
var i = F(ClrFilter.Eq("data/pictures/iv", "guid"));
var o = C("{ 'do.6.iv' : 'guid' }");
Assert.Equal(o, i);
@ -201,7 +202,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_query_with_full_text()
{
var i = Q(new Query { FullText = "Hello my World" });
var i = Q(new ClrQuery { FullText = "Hello my World" });
var o = C("{ '$text' : { '$search' : 'Hello my World' } }");
Assert.Equal(o, i);
@ -228,7 +229,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_take_statement()
{
var query = new Query { Take = 3 };
var query = new ClrQuery { Take = 3 };
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
cursor.ContentTake(query.AdjustToModel(schemaDef, false));
@ -240,7 +241,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
[Fact]
public void Should_make_skip_statement()
{
var query = new Query { Skip = 3 };
var query = new ClrQuery { Skip = 3 };
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
cursor.ContentSkip(query.AdjustToModel(schemaDef, false));
@ -254,9 +255,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
return value.Replace('\'', '"');
}
private string F(FilterNode filter, bool useDraft = false)
private string F(FilterNode<ClrValue> filter, bool useDraft = false)
{
return Q(new Query { Filter = filter }, useDraft);
return Q(new ClrQuery { Filter = filter }, useDraft);
}
private string S(params SortNode[] sorts)
@ -271,12 +272,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
i = sortDefinition.Render(Serializer, Registry).ToString();
});
cursor.ContentSort(new Query { Sort = sorts.ToList() }.AdjustToModel(schemaDef, false));
cursor.ContentSort(new ClrQuery { Sort = sorts.ToList() }.AdjustToModel(schemaDef, false));
return i;
}
private string Q(Query query, bool useDraft = false)
private string Q(ClrQuery query, bool useDraft = false)
{
var rendered =
query.AdjustToModel(schemaDef, useDraft).BuildFilter<MongoContentEntity>().Filter

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

@ -43,7 +43,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
A.CallTo(() => tagService.GetTagIdsAsync(appId.Id, TagGroups.Schemas(schemaId.Id), A<HashSet<string>>.That.Contains("name1")))
.Returns(new Dictionary<string, string> { ["name1"] = "id1" });
var source = FilterBuilder.Eq("data.tags2.iv", "name1");
var source = ClrFilter.Eq("data.tags2.iv", "name1");
var result = FilterTagTransformer.Transform(source, appId.Id, schema, tagService);
Assert.Equal("data.tags2.iv == 'id1'", result.ToString());
@ -55,7 +55,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
A.CallTo(() => tagService.GetTagIdsAsync(appId.Id, TagGroups.Assets, A<HashSet<string>>.That.Contains("name1")))
.Returns(new Dictionary<string, string>());
var source = FilterBuilder.Eq("data.tags2.iv", "name1");
var source = ClrFilter.Eq("data.tags2.iv", "name1");
var result = FilterTagTransformer.Transform(source, appId.Id, schema, tagService);
Assert.Equal("data.tags2.iv == 'name1'", result.ToString());
@ -64,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
[Fact]
public void Should_not_normalize_other_tags_field()
{
var source = FilterBuilder.Eq("data.tags1.iv", "value");
var source = ClrFilter.Eq("data.tags1.iv", "value");
var result = FilterTagTransformer.Transform(source, appId.Id, schema, tagService);
Assert.Equal("data.tags1.iv == 'value'", result.ToString());
@ -76,7 +76,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
[Fact]
public void Should_not_normalize_other_typed_field()
{
var source = FilterBuilder.Eq("data.string.iv", "value");
var source = ClrFilter.Eq("data.string.iv", "value");
var result = FilterTagTransformer.Transform(source, appId.Id, schema, tagService);
Assert.Equal("data.string.iv == 'value'", result.ToString());
@ -88,7 +88,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
[Fact]
public void Should_not_normalize_non_data_field()
{
var source = FilterBuilder.Eq("no.data", "value");
var source = ClrFilter.Eq("no.data", "value");
var result = FilterTagTransformer.Transform(source, appId.Id, schema, tagService);
Assert.Equal("no.data == 'value'", result.ToString());

2
tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs

@ -12,7 +12,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers
{
public static class AExtensions
{
public static Query Is(this INegatableArgumentConstraintManager<Query> that, string query)
public static ClrQuery Is(this INegatableArgumentConstraintManager<ClrQuery> that, string query)
{
return that.Matches(x => x.ToString() == query);
}

8
tests/Squidex.Infrastructure.Tests/Queries/PascalCasePathConverterTests.cs

@ -14,8 +14,8 @@ namespace Squidex.Infrastructure.Queries
[Fact]
public void Should_convert_property()
{
var source = FilterBuilder.Eq("property", 1);
var result = PascalCasePathConverter.Transform(source);
var source = ClrFilter.Eq("property", 1);
var result = PascalCasePathConverter<ClrValue>.Transform(source);
Assert.Equal("Property == 1", result.ToString());
}
@ -23,8 +23,8 @@ namespace Squidex.Infrastructure.Queries
[Fact]
public void Should_convert_properties()
{
var source = FilterBuilder.Eq("root.child", 1);
var result = PascalCasePathConverter.Transform(source);
var source = ClrFilter.Eq("root.child", 1);
var result = PascalCasePathConverter<ClrValue>.Transform(source);
Assert.Equal("Root.Child == 1", result.ToString());
}

Loading…
Cancel
Save