From fc9ff223d650b2f903a6216cdbb7a2303a65d27f Mon Sep 17 00:00:00 2001 From: Austin Drenski Date: Tue, 15 May 2018 12:51:51 -0400 Subject: [PATCH] Addressing code review comments #2 (2018-05-15). --- .../Internal/NpgsqlRangeTranslator.cs | 49 +--- .../Query/RangeQueryNpgsqlFixture.cs | 158 ------------ .../Query/RangeQueryNpgsqlTest.cs | 244 +++++++++++++++--- 3 files changed, 219 insertions(+), 232 deletions(-) delete mode 100644 test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlFixture.cs diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlRangeTranslator.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlRangeTranslator.cs index 30abcf839..39127c444 100644 --- a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlRangeTranslator.cs +++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlRangeTranslator.cs @@ -23,7 +23,6 @@ #endregion -using System; using System.Linq.Expressions; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Query.ExpressionTranslators; @@ -41,70 +40,46 @@ public class NpgsqlRangeTranslator : IMethodCallTranslator { /// [CanBeNull] - public Expression Translate(MethodCallExpression methodCallExpression) => - TryTranslateOperator(methodCallExpression); - - /// - /// Attempts to translate the as a PostgreSQL range operator. - /// - /// The to be translated. - /// - /// The expression if successful; otherwise, null. - /// - [CanBeNull] - static Expression TryTranslateOperator([NotNull] MethodCallExpression expression) + public Expression Translate(MethodCallExpression expression) { switch (expression.Method.Name) { case nameof(NpgsqlRangeExtensions.Contains): - return MakeBinaryExpression(expression, "@>", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "@>", typeof(bool)); case nameof(NpgsqlRangeExtensions.ContainedBy): - return MakeBinaryExpression(expression, "<@", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "<@", typeof(bool)); case nameof(NpgsqlRangeExtensions.Overlaps): - return MakeBinaryExpression(expression, "&&", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "&&", typeof(bool)); case nameof(NpgsqlRangeExtensions.IsStrictlyLeftOf): - return MakeBinaryExpression(expression, "<<", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "<<", typeof(bool)); case nameof(NpgsqlRangeExtensions.IsStrictlyRightOf): - return MakeBinaryExpression(expression, ">>", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], ">>", typeof(bool)); case nameof(NpgsqlRangeExtensions.DoesNotExtendRightOf): - return MakeBinaryExpression(expression, "&<", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "&<", typeof(bool)); case nameof(NpgsqlRangeExtensions.DoesNotExtendLeftOf): - return MakeBinaryExpression(expression, "&>", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "&>", typeof(bool)); case nameof(NpgsqlRangeExtensions.IsAdjacentTo): - return MakeBinaryExpression(expression, "-|-", typeof(bool)); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "-|-", typeof(bool)); case nameof(NpgsqlRangeExtensions.Union): - return MakeBinaryExpression(expression, "+", expression.Arguments[0].Type); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "+", expression.Arguments[0].Type); case nameof(NpgsqlRangeExtensions.Intersect): - return MakeBinaryExpression(expression, "*", expression.Arguments[0].Type); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "*", expression.Arguments[0].Type); case nameof(NpgsqlRangeExtensions.Except): - return MakeBinaryExpression(expression, "-", expression.Arguments[0].Type); + return new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], "-", expression.Arguments[0].Type); default: return null; } } - - /// - /// Constructs a . - /// - /// The containing two parameters. - /// The symbolic operator for PostgreSQL. - /// The return type of the operator. - /// - /// A . - /// - [NotNull] - static Expression MakeBinaryExpression([NotNull] MethodCallExpression expression, [NotNull] string symbol, [NotNull] Type returnType) => - new CustomBinaryExpression(expression.Arguments[0], expression.Arguments[1], symbol, returnType); } } diff --git a/test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlFixture.cs b/test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlFixture.cs deleted file mode 100644 index 9ee91b1e8..000000000 --- a/test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlFixture.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.TestUtilities; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Npgsql.EntityFrameworkCore.PostgreSQL.TestUtilities; -using NpgsqlTypes; - -namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query -{ - /// - /// Represents a fixture suitable for testing range operators. - /// - public class RangeQueryNpgsqlFixture : IDisposable - { - /// - /// The used for testing. - /// - private readonly NpgsqlTestStore _testStore; - - /// - /// The used for testing. - /// - private readonly DbContextOptions _options; - - /// - /// The logger factory used for testing. - /// - public TestSqlLoggerFactory TestSqlLoggerFactory { get; } - - /// - /// Initializes a . - /// - // ReSharper disable once UnusedMember.Global - public RangeQueryNpgsqlFixture() - { - TestSqlLoggerFactory = new TestSqlLoggerFactory(); - - _testStore = NpgsqlTestStore.CreateScratch(); - - _options = - new DbContextOptionsBuilder() - .UseNpgsql(_testStore.ConnectionString, b => b.ApplyConfiguration()) - .UseInternalServiceProvider( - new ServiceCollection() - .AddEntityFrameworkNpgsql() - .AddSingleton(TestSqlLoggerFactory) - .BuildServiceProvider()) - .Options; - - using (RangeContext context = CreateContext()) - { - context.Database.EnsureCreated(); - - context.RangeTestEntities.AddRange( - new RangeTestEntity - { - Id = 1, - // (0, 10) - Range = new NpgsqlRange(0, false, false, 10, false, false), - }, - new RangeTestEntity - { - Id = 2, - // [0, 10) - Range = new NpgsqlRange(0, true, false, 10, false, false) - }, - new RangeTestEntity - { - Id = 3, - // [0, 10] - Range = new NpgsqlRange(0, true, false, 10, true, false) - }, - new RangeTestEntity - { - Id = 4, - // [0, ∞) - Range = new NpgsqlRange(0, true, false, 0, false, true) - }, - new RangeTestEntity - { - Id = 5, - // (-∞, 10] - Range = new NpgsqlRange(0, false, true, 10, true, false) - }, - new RangeTestEntity - { - Id = 6, - // (-∞, ∞) - Range = new NpgsqlRange(0, false, true, 0, false, true) - }, - new RangeTestEntity - { - Id = 7, - // (-∞, ∞) - Range = new NpgsqlRange(0, false, true, 0, false, true) - }); - - context.SaveChanges(); - } - } - - /// - /// Creates a new . - /// - /// - /// A for testing. - /// - public RangeContext CreateContext() - { - return new RangeContext(_options); - } - - /// - public void Dispose() - { - _testStore.Dispose(); - } - } - - /// - /// Represents an entity suitable for testing range operators. - /// - public class RangeTestEntity - { - /// - /// The primary key. - /// - public int Id { get; set; } - - /// - /// The range of integers. - /// - public NpgsqlRange Range { get; set; } - } - - /// - /// Represents a database suitable for testing range operators. - /// - public class RangeContext : DbContext - { - /// - /// Represents a set of entities with properties. - /// - public DbSet RangeTestEntities { get; set; } - - /// - /// Initializes a . - /// - /// - /// The options to be used for configuration. - /// - public RangeContext(DbContextOptions options) : base(options) { } - - /// - protected override void OnModelCreating(ModelBuilder builder) { } - } -} diff --git a/test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlTest.cs b/test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlTest.cs index b70a11676..c31d32016 100644 --- a/test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/RangeQueryNpgsqlTest.cs @@ -1,5 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Npgsql.EntityFrameworkCore.PostgreSQL.TestUtilities; using NpgsqlTypes; using Xunit; @@ -8,40 +14,13 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Query /// /// Provides unit tests for range operator translations. /// - public class RangeQueryNpgsqlTest : IClassFixture + public class RangeQueryNpgsqlTest : IClassFixture { /// /// Provides resources for unit tests. /// RangeQueryNpgsqlFixture Fixture { get; } - /// - /// Provides theory data for integers. - /// - public static IEnumerable IntegerTheoryData => Enumerable.Range(-10, 10).Select(x => new object[] { x }); - - /// - /// Provides theory data for ranges. - /// - public static IEnumerable RangeTheoryData => - new List - { - // (0,5) - new object[] { new NpgsqlRange(0, false, false, 5, false, false) }, - // [0,5] - new object[] { new NpgsqlRange(0, true, false, 5, true, false) }, - // (,) - new object[] { new NpgsqlRange(0, false, true, 0, false, true) }, - // (,) - new object[] { new NpgsqlRange(0, false, true, 5, false, true) }, - // (0,) - new object[] { new NpgsqlRange(0, false, false, 0, false, true) }, - // (0,) - new object[] { new NpgsqlRange(0, false, false, 5, false, true) }, - // (,5) - new object[] { new NpgsqlRange(0, false, true, 5, false, false) } - }; - /// /// Initializes resources for unit tests. /// @@ -52,14 +31,7 @@ public RangeQueryNpgsqlTest(RangeQueryNpgsqlFixture fixture) Fixture.TestSqlLoggerFactory.Clear(); } - /// - /// Asserts that the SQL fragment appears in the logs. - /// - /// The SQL statement or fragment to search for in the logs. - public void AssertContainsSql(string sql) - { - Assert.Contains(sql, Fixture.TestSqlLoggerFactory.Sql); - } + #region Tests /// /// Tests translation for . @@ -517,5 +489,203 @@ public void RangeExceptRange(NpgsqlRange range) AssertContainsSql("SELECT x.\"Range\" - @__range_0"); } } + + #endregion Tests + + #region TheoryData + + /// + /// Provides theory data for integers. + /// + public static IEnumerable IntegerTheoryData => Enumerable.Range(-10, 10).Select(x => new object[] { x }); + + /// + /// Provides theory data for ranges. + /// + public static IEnumerable RangeTheoryData => + new List + { + // (0,5) + new object[] { new NpgsqlRange(0, false, false, 5, false, false) }, + // [0,5] + new object[] { new NpgsqlRange(0, true, false, 5, true, false) }, + // (,) + new object[] { new NpgsqlRange(0, false, true, 0, false, true) }, + // (,) + new object[] { new NpgsqlRange(0, false, true, 5, false, true) }, + // (0,) + new object[] { new NpgsqlRange(0, false, false, 0, false, true) }, + // (0,) + new object[] { new NpgsqlRange(0, false, false, 5, false, true) }, + // (,5) + new object[] { new NpgsqlRange(0, false, true, 5, false, false) } + }; + + #endregion + + #region Fixtures + + /// + /// Represents a fixture suitable for testing range operators. + /// + public class RangeQueryNpgsqlFixture : IDisposable + { + /// + /// The used for testing. + /// + private readonly NpgsqlTestStore _testStore; + + /// + /// The used for testing. + /// + private readonly DbContextOptions _options; + + /// + /// The logger factory used for testing. + /// + public TestSqlLoggerFactory TestSqlLoggerFactory { get; } + + /// + /// Initializes a . + /// + // ReSharper disable once UnusedMember.Global + public RangeQueryNpgsqlFixture() + { + TestSqlLoggerFactory = new TestSqlLoggerFactory(); + + _testStore = NpgsqlTestStore.CreateScratch(); + + _options = + new DbContextOptionsBuilder() + .UseNpgsql(_testStore.ConnectionString, b => b.ApplyConfiguration()) + .UseInternalServiceProvider( + new ServiceCollection() + .AddEntityFrameworkNpgsql() + .AddSingleton(TestSqlLoggerFactory) + .BuildServiceProvider()) + .Options; + + using (RangeContext context = CreateContext()) + { + context.Database.EnsureCreated(); + + context.RangeTestEntities.AddRange( + new RangeTestEntity + { + Id = 1, + // (0, 10) + Range = new NpgsqlRange(0, false, false, 10, false, false), + }, + new RangeTestEntity + { + Id = 2, + // [0, 10) + Range = new NpgsqlRange(0, true, false, 10, false, false) + }, + new RangeTestEntity + { + Id = 3, + // [0, 10] + Range = new NpgsqlRange(0, true, false, 10, true, false) + }, + new RangeTestEntity + { + Id = 4, + // [0, ∞) + Range = new NpgsqlRange(0, true, false, 0, false, true) + }, + new RangeTestEntity + { + Id = 5, + // (-∞, 10] + Range = new NpgsqlRange(0, false, true, 10, true, false) + }, + new RangeTestEntity + { + Id = 6, + // (-∞, ∞) + Range = new NpgsqlRange(0, false, true, 0, false, true) + }, + new RangeTestEntity + { + Id = 7, + // (-∞, ∞) + Range = new NpgsqlRange(0, false, true, 0, false, true) + }); + + context.SaveChanges(); + } + } + + /// + /// Creates a new . + /// + /// + /// A for testing. + /// + public RangeContext CreateContext() + { + return new RangeContext(_options); + } + + /// + public void Dispose() + { + _testStore.Dispose(); + } + } + + /// + /// Represents an entity suitable for testing range operators. + /// + public class RangeTestEntity + { + /// + /// The primary key. + /// + public int Id { get; set; } + + /// + /// The range of integers. + /// + public NpgsqlRange Range { get; set; } + } + + /// + /// Represents a database suitable for testing range operators. + /// + public class RangeContext : DbContext + { + /// + /// Represents a set of entities with properties. + /// + public DbSet RangeTestEntities { get; set; } + + /// + /// Initializes a . + /// + /// + /// The options to be used for configuration. + /// + public RangeContext(DbContextOptions options) : base(options) { } + + /// + protected override void OnModelCreating(ModelBuilder builder) { } + } + + #endregion + + #region Helpers + + /// + /// Asserts that the SQL fragment appears in the logs. + /// + /// The SQL statement or fragment to search for in the logs. + public void AssertContainsSql(string sql) + { + Assert.Contains(sql, Fixture.TestSqlLoggerFactory.Sql); + } + + #endregion } }