Browse Source

Support for IN Queries.

pull/320/head
Sebastian Stehle 7 years ago
parent
commit
d24a083154
  1. 10
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/FindExtensions.cs
  2. 4
      src/Squidex.Domain.Apps.Entities/Assets/Queries/FilterTagTransformer.cs
  3. 4
      src/Squidex.Domain.Apps.Entities/Contents/Queries/FilterTagTransformer.cs
  4. 19
      src/Squidex.Infrastructure.MongoDb/MongoDb/OData/FilterVisitor.cs
  5. 54
      src/Squidex.Infrastructure/Queries/FilterBuilder.cs
  6. 41
      src/Squidex.Infrastructure/Queries/FilterComparison.cs
  7. 1
      src/Squidex.Infrastructure/Queries/FilterOperator.cs
  8. 138
      src/Squidex.Infrastructure/Queries/FilterValue.cs
  9. 3
      src/Squidex.Infrastructure/Queries/FilterValueType.cs
  10. 117
      src/Squidex.Infrastructure/Queries/OData/ConstantWithTypeVisitor.cs
  11. 47
      src/Squidex.Infrastructure/Queries/OData/FilterVisitor.cs
  12. 2
      src/Squidex.Infrastructure/Queries/PascalCasePathConverter.cs
  13. 9
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/MongoDbQueryTests.cs
  14. 72
      tests/Squidex.Infrastructure.Tests/Queries/ODataConversionTests.cs

10
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Visitors/FindExtensions.cs

@ -39,16 +39,16 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Visitors
public override FilterNode Visit(FilterComparison nodeIn)
{
var value = nodeIn.Value;
var value = nodeIn.Rhs.Value;
if (value is Instant instant &&
!string.Equals(nodeIn.Path[0], "mt", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(nodeIn.Path[0], "ct", StringComparison.OrdinalIgnoreCase))
!string.Equals(nodeIn.Lhs[0], "mt", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(nodeIn.Lhs[0], "ct", StringComparison.OrdinalIgnoreCase))
{
value = instant.ToString();
return new FilterComparison(pathConverter(nodeIn.Lhs), nodeIn.Operator, new FilterValue(value.ToString()));
}
return new FilterComparison(pathConverter(nodeIn.Path), nodeIn.Operator, value, nodeIn.ValueType);
return new FilterComparison(pathConverter(nodeIn.Lhs), nodeIn.Operator, nodeIn.Rhs);
}
}

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

@ -34,13 +34,13 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries
public override FilterNode Visit(FilterComparison nodeIn)
{
if (string.Equals(nodeIn.Path[0], nameof(IAssetEntity.Tags), StringComparison.OrdinalIgnoreCase) && nodeIn.Value is string stringValue)
if (string.Equals(nodeIn.Lhs[0], nameof(IAssetEntity.Tags), StringComparison.OrdinalIgnoreCase) && nodeIn.Rhs.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.Path, nodeIn.Operator, normalized, FilterValueType.String);
return new FilterComparison(nodeIn.Lhs, nodeIn.Operator, new FilterValue(normalized));
}
}

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

@ -39,13 +39,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
public override FilterNode Visit(FilterComparison nodeIn)
{
if (nodeIn.Value is string stringValue && IsDataPath(nodeIn.Path) && IsTagField(nodeIn.Path))
if (nodeIn.Rhs.Value is string stringValue && IsDataPath(nodeIn.Lhs) && IsTagField(nodeIn.Lhs))
{
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 new FilterComparison(nodeIn.Lhs, nodeIn.Operator, new FilterValue(normalized));
}
}

19
src/Squidex.Infrastructure.MongoDb/MongoDb/OData/FilterVisitor.cs

@ -6,6 +6,7 @@
// ==========================================================================
using System;
using System.Collections;
using System.Linq;
using MongoDB.Bson;
using MongoDB.Driver;
@ -46,7 +47,7 @@ namespace Squidex.Infrastructure.MongoDb.OData
public override FilterDefinition<T> Visit(FilterComparison nodeIn)
{
var propertyName = string.Join(".", nodeIn.Path);
var propertyName = string.Join(".", nodeIn.Lhs);
switch (nodeIn.Operator)
{
@ -57,17 +58,19 @@ namespace Squidex.Infrastructure.MongoDb.OData
case FilterOperator.EndsWith:
return Filter.Regex(propertyName, BuildRegex(nodeIn, s => s + "$"));
case FilterOperator.Equals:
return Filter.Eq(propertyName, nodeIn.Value);
return Filter.Eq(propertyName, nodeIn.Rhs.Value);
case FilterOperator.GreaterThan:
return Filter.Gt(propertyName, nodeIn.Value);
return Filter.Gt(propertyName, nodeIn.Rhs.Value);
case FilterOperator.GreaterThanOrEqual:
return Filter.Gte(propertyName, nodeIn.Value);
return Filter.Gte(propertyName, nodeIn.Rhs.Value);
case FilterOperator.LessThan:
return Filter.Lt(propertyName, nodeIn.Value);
return Filter.Lt(propertyName, nodeIn.Rhs.Value);
case FilterOperator.LessThanOrEqual:
return Filter.Lte(propertyName, nodeIn.Value);
return Filter.Lte(propertyName, nodeIn.Rhs.Value);
case FilterOperator.NotEquals:
return Filter.Ne(propertyName, nodeIn.Value);
return Filter.Ne(propertyName, nodeIn.Rhs.Value);
case FilterOperator.In:
return Filter.In(propertyName, ((IList)nodeIn.Rhs.Value).OfType<object>());
}
throw new NotSupportedException();
@ -75,7 +78,7 @@ namespace Squidex.Infrastructure.MongoDb.OData
private static BsonRegularExpression BuildRegex(FilterComparison node, Func<string, string> formatter)
{
return new BsonRegularExpression(formatter(node.Value.ToString()), "i");
return new BsonRegularExpression(formatter(node.Rhs.Value.ToString()), "i");
}
}
}

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

@ -5,6 +5,9 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Linq;
using NodaTime;
namespace Squidex.Infrastructure.Queries
{
public static class FilterBuilder
@ -19,14 +22,59 @@ namespace Squidex.Infrastructure.Queries
return new FilterJunction(FilterJunctionType.Or, operands);
}
public static FilterComparison Eq(string path, object value)
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);
}
private static FilterComparison Binary(string path, FilterOperator @operator, object value)
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, value, FilterValueType.String);
return new FilterComparison(path.Split('.', '/'), @operator, new FilterValue(value));
}
}
}

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

@ -11,25 +11,20 @@ namespace Squidex.Infrastructure.Queries
{
public sealed class FilterComparison : FilterNode
{
public IReadOnlyList<string> Path { get; }
public IReadOnlyList<string> Lhs { get; }
public FilterOperator Operator { get; }
public FilterValueType ValueType { get; }
public FilterValue Rhs { get; }
public object Value { get; }
public FilterComparison(IReadOnlyList<string> path, FilterOperator @operator, object value, FilterValueType valueType)
public FilterComparison(IReadOnlyList<string> lhs, FilterOperator @operator, FilterValue rhs)
{
Guard.NotNull(path, nameof(path));
Guard.NotEmpty(path, nameof(path));
Guard.NotNull(lhs, nameof(lhs));
Guard.NotEmpty(lhs, nameof(lhs));
Guard.Enum(@operator, nameof(@operator));
Guard.Enum(valueType, nameof(valueType));
Path = path;
Value = value;
ValueType = valueType;
Lhs = lhs;
Rhs = rhs;
Operator = @operator;
}
@ -41,28 +36,30 @@ namespace Squidex.Infrastructure.Queries
public override string ToString()
{
var path = string.Join(".", Path);
var path = string.Join(".", Lhs);
switch (Operator)
{
case FilterOperator.Contains:
return $"contains({path}, {Value})";
return $"contains({path}, {Rhs})";
case FilterOperator.EndsWith:
return $"endsWith({path}, {Value})";
return $"endsWith({path}, {Rhs})";
case FilterOperator.StartsWith:
return $"startsWith({path}, {Value})";
return $"startsWith({path}, {Rhs})";
case FilterOperator.Equals:
return $"{path} == {Value}";
return $"{path} == {Rhs}";
case FilterOperator.NotEquals:
return $"{path} != {Value}";
return $"{path} != {Rhs}";
case FilterOperator.GreaterThan:
return $"{path} > {Value}";
return $"{path} > {Rhs}";
case FilterOperator.GreaterThanOrEqual:
return $"{path} >= {Value}";
return $"{path} >= {Rhs}";
case FilterOperator.LessThan:
return $"{path} < {Value}";
return $"{path} < {Rhs}";
case FilterOperator.LessThanOrEqual:
return $"{path} <= {Value}";
return $"{path} <= {Rhs}";
case FilterOperator.In:
return $"{path} in {Rhs}";
default:
return string.Empty;
}

1
src/Squidex.Infrastructure/Queries/FilterOperator.cs

@ -14,6 +14,7 @@ namespace Squidex.Infrastructure.Queries
Equals,
GreaterThan,
GreaterThanOrEqual,
In,
LessThan,
LessThanOrEqual,
NotEquals,

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

@ -0,0 +1,138 @@
// ==========================================================================
// 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.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>().ToArray())}]";
}
else if (Value == null)
{
return "<Null>";
}
else
{
return Value.ToString();
}
}
}
}

3
src/Squidex.Infrastructure/Queries/FilterValueType.cs

@ -16,6 +16,7 @@ namespace Squidex.Infrastructure.Queries
Int32,
Int64,
Single,
String
String,
Null
}
}

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

@ -6,6 +6,7 @@
// ==========================================================================
using System;
using System.Linq;
using Microsoft.OData;
using Microsoft.OData.Edm;
using Microsoft.OData.UriParser;
@ -14,7 +15,7 @@ using NodaTime.Text;
namespace Squidex.Infrastructure.Queries.OData
{
public sealed class ConstantWithTypeVisitor : QueryNodeVisitor<(object Value, FilterValueType ValueType)>
public sealed class ConstantWithTypeVisitor : QueryNodeVisitor<FilterValue>
{
private static readonly IEdmPrimitiveType BooleanType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.Boolean);
private static readonly IEdmPrimitiveType DateTimeType = EdmCoreModel.Instance.GetPrimitiveType(EdmPrimitiveTypeKind.DateTimeOffset);
@ -31,88 +32,142 @@ namespace Squidex.Infrastructure.Queries.OData
{
}
public static (object Value, FilterValueType ValueType) Visit(QueryNode node)
public static FilterValue Visit(QueryNode node)
{
return node.Accept(Instance);
}
public override (object Value, FilterValueType ValueType) Visit(ConvertNode nodeIn)
public override FilterValue Visit(ConvertNode nodeIn)
{
if (nodeIn.TypeReference.Definition == BooleanType)
{
return (bool.Parse(ConstantVisitor.Visit(nodeIn.Source).ToString()), FilterValueType.Boolean);
var value = ConstantVisitor.Visit(nodeIn.Source);
return new FilterValue(bool.Parse(value.ToString()));
}
if (nodeIn.TypeReference.Definition == GuidType)
{
return (Guid.Parse(ConstantVisitor.Visit(nodeIn.Source).ToString()), FilterValueType.Guid);
var value = ConstantVisitor.Visit(nodeIn.Source);
return new FilterValue(Guid.Parse(value.ToString()));
}
if (nodeIn.TypeReference.Definition == DateTimeType)
{
var value = ConstantVisitor.Visit(nodeIn.Source);
if (value is DateTimeOffset dateTimeOffset)
{
return (Instant.FromDateTimeOffset(dateTimeOffset), FilterValueType.Instant);
}
return new FilterValue(ParseInstant(value));
}
throw new NotSupportedException();
}
public override FilterValue Visit(CollectionConstantNode nodeIn)
{
if (nodeIn.ItemType.Definition == DateTimeType)
{
return new FilterValue(nodeIn.Collection.Select(x => ParseInstant(x.Value)).ToList());
}
if (nodeIn.ItemType.Definition == GuidType)
{
return new FilterValue(nodeIn.Collection.Select(x => (Guid)x.Value).ToList());
}
if (value is DateTime dateTime)
{
return (Instant.FromDateTimeUtc(DateTime.SpecifyKind(dateTime, DateTimeKind.Utc)), FilterValueType.Instant);
}
if (nodeIn.ItemType.Definition == BooleanType)
{
return new FilterValue(nodeIn.Collection.Select(x => (bool)x.Value).ToList());
}
if (value is Date date)
{
return (Instant.FromUtc(date.Year, date.Month, date.Day, 0, 0), FilterValueType.Instant);
}
if (nodeIn.ItemType.Definition == SingleType)
{
return new FilterValue(nodeIn.Collection.Select(x => (float)x.Value).ToList());
}
if (nodeIn.ItemType.Definition == DoubleType)
{
return new FilterValue(nodeIn.Collection.Select(x => (double)x.Value).ToList());
}
var parseResult = InstantPattern.General.Parse(Visit(nodeIn.Source).ToString());
if (nodeIn.ItemType.Definition == Int32Type)
{
return new FilterValue(nodeIn.Collection.Select(x => (int)x.Value).ToList());
}
if (!parseResult.Success)
{
throw new ODataException("Datetime is not in a valid format. Use ISO 8601");
}
if (nodeIn.ItemType.Definition == Int64Type)
{
return new FilterValue(nodeIn.Collection.Select(x => (long)x.Value).ToList());
}
return (parseResult.Value, FilterValueType.Instant);
if (nodeIn.ItemType.Definition == StringType)
{
return new FilterValue(nodeIn.Collection.Select(x => (string)x.Value).ToList());
}
return base.Visit(nodeIn);
throw new NotSupportedException();
}
public override (object Value, FilterValueType ValueType) Visit(ConstantNode nodeIn)
public override FilterValue Visit(ConstantNode nodeIn)
{
if (nodeIn.TypeReference.Definition == BooleanType)
{
return (nodeIn.Value, FilterValueType.Boolean);
return new FilterValue((bool)nodeIn.Value);
}
if (nodeIn.TypeReference.Definition == SingleType)
{
return (nodeIn.Value, FilterValueType.Single);
return new FilterValue((float)nodeIn.Value);
}
if (nodeIn.TypeReference.Definition == DoubleType)
{
return (nodeIn.Value, FilterValueType.Double);
return new FilterValue((double)nodeIn.Value);
}
if (nodeIn.TypeReference.Definition == Int32Type)
{
return (nodeIn.Value, FilterValueType.Int32);
return new FilterValue((int)nodeIn.Value);
}
if (nodeIn.TypeReference.Definition == Int64Type)
{
return (nodeIn.Value, FilterValueType.Int64);
return new FilterValue((long)nodeIn.Value);
}
if (nodeIn.TypeReference.Definition == StringType)
{
return (nodeIn.Value, FilterValueType.String);
return new FilterValue((string)nodeIn.Value);
}
throw new NotSupportedException();
}
private Instant ParseInstant(object value)
{
if (value is DateTimeOffset dateTimeOffset)
{
return Instant.FromDateTimeOffset(dateTimeOffset.Add(dateTimeOffset.Offset));
}
if (value is DateTime dateTime)
{
return Instant.FromDateTimeUtc(DateTime.SpecifyKind(dateTime, DateTimeKind.Utc));
}
if (value is Date date)
{
return Instant.FromUtc(date.Year, date.Month, date.Day, 0, 0);
}
var parseResult = InstantPattern.General.Parse(value.ToString());
if (!parseResult.Success)
{
throw new ODataException("Datetime is not in a valid format. Use ISO 8601");
}
return parseResult.Value;
}
}
}

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

@ -39,6 +39,13 @@ namespace Squidex.Infrastructure.Queries.OData
throw new NotSupportedException();
}
public override FilterNode Visit(InNode nodeIn)
{
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.In, value);
}
public override FilterNode Visit(SingleValueFunctionCallNode nodeIn)
{
var fieldNode = nodeIn.Parameters.ElementAt(0);
@ -46,23 +53,23 @@ namespace Squidex.Infrastructure.Queries.OData
if (string.Equals(nodeIn.Name, "endswith", StringComparison.OrdinalIgnoreCase))
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(valueNode);
var value = ConstantWithTypeVisitor.Visit(valueNode);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.EndsWith, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.EndsWith, value);
}
if (string.Equals(nodeIn.Name, "startswith", StringComparison.OrdinalIgnoreCase))
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(valueNode);
var value = ConstantWithTypeVisitor.Visit(valueNode);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.StartsWith, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.StartsWith, value);
}
if (string.Equals(nodeIn.Name, "contains", StringComparison.OrdinalIgnoreCase))
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(valueNode);
var value = ConstantWithTypeVisitor.Visit(valueNode);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.Contains, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(fieldNode), FilterOperator.Contains, value);
}
throw new NotSupportedException();
@ -84,9 +91,9 @@ namespace Squidex.Infrastructure.Queries.OData
{
var regexFilter = Visit(functionNode);
var (value, _) = ConstantWithTypeVisitor.Visit(nodeIn.Right);
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
if (value is bool booleanRight)
if (value.ValueType == FilterValueType.Boolean && value.Value is bool booleanRight)
{
if ((nodeIn.OperatorKind == BinaryOperatorKind.Equal && !booleanRight) ||
(nodeIn.OperatorKind == BinaryOperatorKind.NotEqual && booleanRight))
@ -101,44 +108,44 @@ namespace Squidex.Infrastructure.Queries.OData
{
if (nodeIn.OperatorKind == BinaryOperatorKind.NotEqual)
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(nodeIn.Right);
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.NotEquals, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.NotEquals, value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.Equal)
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(nodeIn.Right);
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.Equals, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.Equals, value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.LessThan)
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(nodeIn.Right);
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.LessThan, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.LessThan, value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.LessThanOrEqual)
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(nodeIn.Right);
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.LessThanOrEqual, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.LessThanOrEqual, value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThan)
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(nodeIn.Right);
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.GreaterThan, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.GreaterThan, value);
}
if (nodeIn.OperatorKind == BinaryOperatorKind.GreaterThanOrEqual)
{
var (value, valueType) = ConstantWithTypeVisitor.Visit(nodeIn.Right);
var value = ConstantWithTypeVisitor.Visit(nodeIn.Right);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.GreaterThanOrEqual, value, valueType);
return new FilterComparison(PropertyPathVisitor.Visit(nodeIn.Left), FilterOperator.GreaterThanOrEqual, value);
}
}

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

@ -24,7 +24,7 @@ namespace Squidex.Infrastructure.Queries
public override FilterNode Visit(FilterComparison nodeIn)
{
return new FilterComparison(nodeIn.Path.Select(x => x.ToPascalCase()).ToList(), nodeIn.Operator, nodeIn.Value, nodeIn.ValueType);
return new FilterComparison(nodeIn.Lhs.Select(x => x.ToPascalCase()).ToList(), nodeIn.Operator, nodeIn.Rhs);
}
}
}

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

@ -125,6 +125,15 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
Assert.Equal(o, i);
}
[Fact]
public void Should_make_query_with_version_and_list()
{
var i = F(FilterBuilder.In("version", 0L, 2L, 5L));
var o = C("{ 'vs' : { '$in' : [NumberLong(0), NumberLong(2), NumberLong(5)] } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_make_query_from_draft()
{

72
tests/Squidex.Infrastructure.Tests/Queries/ODataConversionTests.cs

@ -58,6 +58,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_datetime_list()
{
var i = Q("$filter=created in ('1988-01-19T12:00:00Z')");
var o = C("Filter: created in [1988-01-19T12:00:00Z]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_date()
{
@ -67,6 +76,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_date_list()
{
var i = Q("$filter=created in ('1988-01-19')");
var o = C("Filter: created in [1988-01-19T00:00:00Z]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_guid()
{
@ -76,6 +94,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_guid_list()
{
var i = Q("$filter=id in ('B5FE25E3-B262-4B17-91EF-B3772A6B62BB')");
var o = C("Filter: id in [b5fe25e3-b262-4b17-91ef-b3772a6b62bb]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_string()
{
@ -85,6 +112,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_string_list()
{
var i = Q("$filter=firstName in ('Dagobert')");
var o = C("Filter: firstName in [Dagobert]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_boolean()
{
@ -94,6 +130,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_boolean_list()
{
var i = Q("$filter=isComicFigure in (true)");
var o = C("Filter: isComicFigure in [True]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_int32()
{
@ -103,6 +148,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_int32_list()
{
var i = Q("$filter=age in (60)");
var o = C("Filter: age in [60]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_int64()
{
@ -112,6 +166,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_int64_list()
{
var i = Q("$filter=incomeCents in (31543143513456789)");
var o = C("Filter: incomeCents in [31543143513456789]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_double()
{
@ -121,6 +184,15 @@ namespace Squidex.Infrastructure.Queries
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_when_type_is_double_list()
{
var i = Q("$filter=incomeMio in (5634474356.1233)");
var o = C("Filter: incomeMio in [5634474356.1233]");
Assert.Equal(o, i);
}
[Fact]
public void Should_parse_filter_with_negation()
{

Loading…
Cancel
Save