diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Linq/CosmosLinqJsonConverterTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Linq/CosmosLinqJsonConverterTests.cs index e4f90f1957..ca2e12c8da 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Linq/CosmosLinqJsonConverterTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Linq/CosmosLinqJsonConverterTests.cs @@ -6,7 +6,10 @@ namespace Microsoft.Azure.Cosmos.Linq { using System; using System.Globalization; + using System.IO; + using System.Linq; using System.Linq.Expressions; + using global::Azure.Core.Serialization; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -30,6 +33,104 @@ public void DateTimeKindIsPreservedTest() Assert.AreEqual("(a[\"StartDate\"] <= \"2022-05-26\")", sql); } + [TestMethod] + public void EnumIsPreservedAsINTest() + { + // Arrange + CosmosLinqSerializerOptions options = new() + { + //CustomCosmosSerializer = new TestCustomJsonSerializer() + }; + + // Act + TestEnum[] values = new[] { TestEnum.One, TestEnum.Two }; + Expression> expr = a => values.Contains(a.Value); + + string sql = SqlTranslator.TranslateExpression(expr.Body, options); + + // Assert + // Assert.AreEqual("(a[\"Value\"] IN (\"One\", \"Two\"))", sql); // <- TODO - Desired Behavior with CustomSerializer + Assert.AreEqual("(a[\"Value\"] IN (0, 1))", sql); // <- Actual behavior, with ability to set custom serializor reverted + } + + [TestMethod] + public void EnumIsPreservedAsEQUALSTest() + { + // Arrange + CosmosLinqSerializerOptions options = new() + { + // CustomCosmosSerializer = new TestCustomJsonSerializer() + }; + + // Act + TestEnum statusValue = TestEnum.One; + Expression> expr = a => a.Value == statusValue; + + string sql = SqlTranslator.TranslateExpression(expr.Body, options); + + // Assert + // Assert.AreEqual("(a[\"Value\"] = \"One\")", sql); // <- THIS is the correct value, if we are able to use the custom serializer + Assert.AreEqual("(a[\"Value\"] = 0)", sql); // <- THIS is the current mis-behavior of the SDK + } + + [TestMethod] + public void EnumIsPreservedAsEXPRESSIONTest() + { + // Arrange + CosmosLinqSerializerOptions options = new() + { + // CustomCosmosSerializer = new TestCustomJsonSerializer() + }; + + // Act + + // Get status constant + ConstantExpression status = Expression.Constant(TestEnum.One); + + // Get member access expression + ParameterExpression arg = Expression.Parameter(typeof(TestEnumNewtonsoftDocument), "a"); + + // Access the value property + MemberExpression docValueExpression = Expression.MakeMemberAccess( + arg, + typeof(TestEnumNewtonsoftDocument).GetProperty(nameof(TestEnumNewtonsoftDocument.Value))! + ); + + // Create comparison expression + BinaryExpression expression = Expression.Equal( + docValueExpression, + status + ); + + // Create lambda expression + Expression> lambda = + Expression.Lambda>(expression, arg); + + string sql = SqlTranslator.TranslateExpression(lambda.Body, options); + + // Assert + Assert.AreEqual("(a[\"Value\"] = \"One\")", sql); + } + + enum TestEnum + { + One, + Two, + Three, + } + + class TestEnumDocument + { + [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumConverter))] // TODO: Remove this once we have the ability to use custom serializer for LINQ queries + public TestEnum Value { get; set; } + } + + class TestEnumNewtonsoftDocument + { + [JsonConverter(typeof(StringEnumConverter))] + public TestEnum Value { get; set; } + } + class TestDocument { [JsonConverter(typeof(DateJsonConverter))] @@ -50,5 +151,54 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s } } } + + /// + // See: https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos.Samples/Usage/SystemTextJson/CosmosSystemTextJsonSerializer.cs + /// + class TestCustomJsonSerializer : CosmosSerializer + { + private readonly JsonObjectSerializer systemTextJsonSerializer; + + public static readonly System.Text.Json.JsonSerializerOptions JsonOptions = new() + { + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true, + Converters = { + new System.Text.Json.Serialization.JsonStringEnumConverter(), + } + }; + + public TestCustomJsonSerializer() + { + this.systemTextJsonSerializer = new JsonObjectSerializer(JsonOptions); + } + + public override T FromStream(Stream stream) + { + using (stream) + { + if (stream.CanSeek && stream.Length == 0) + { + return default; + } + + if (typeof(Stream).IsAssignableFrom(typeof(T))) + { + return (T)(object)stream; + } + + return (T)this.systemTextJsonSerializer.Deserialize(stream, typeof(T), default); + } + } + + public override Stream ToStream(T input) + { + MemoryStream stream = new (); + + this.systemTextJsonSerializer.Serialize(stream, input, typeof(T), default); + stream.Position = 0; + return stream; + } + } } }