From 4d98cac49edc88054981318bd8ed2f02b1b58a71 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sun, 7 Feb 2021 18:23:29 +0000 Subject: [PATCH 01/19] Adding enums and type for postgresxl distribute by clause. --- .../PostgresXlDistributeByAnnotationNames.cs | 14 ++++ .../Metadata/PostgresXlDistributeBy.cs | 79 +++++++++++++++++++ .../PostgresXlDistributeByColumnFunction.cs | 12 +++ .../PostgresXlDistributeByStrategy.cs | 13 +++ .../NpgsqlMigrationsSqlGenerator.cs | 12 +++ 5 files changed, 130 insertions(+) create mode 100644 src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs create mode 100644 src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs create mode 100644 src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs create mode 100644 src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs diff --git a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs new file mode 100644 index 000000000..d0029d30a --- /dev/null +++ b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal +{ + internal static class PostgresXlDistributeByAnnotationNames + { + + public const string Prefix = NpgsqlAnnotationNames.Prefix + "PostgresXL:"; + + public const string DistributeBy = Prefix + "DistributeBy"; + + } +} diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs new file mode 100644 index 000000000..339bc1ea2 --- /dev/null +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs @@ -0,0 +1,79 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; + +namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +{ + public class PostgresXlDistributeBy + { + private const string AnnotationName = PostgresXlDistributeByAnnotationNames.DistributeBy; + + readonly IAnnotatable _annotatable; + + public virtual Annotatable Annotatable + => (Annotatable)_annotatable; + + + public PostgresXlDistributeBy(IAnnotatable annotatable) + => _annotatable = annotatable; + + public virtual PostgresXlDistributeByStrategy DistributionStrategy + { + get => GetData().DistributionStrategy; + [param: NotNull] set + { + (_, var distributeByColumnFunction, var columnName) = GetData(); + SetData(value, distributeByColumnFunction, columnName); + } + } + + public virtual PostgresXlDistributeByColumnFunction DistributeByColumnFunction + { + get => GetData().DistributeByColumnFunction; + [param: NotNull] set + { + var (distributionStrategy, _, columnName) = GetData(); + SetData(distributionStrategy, value, columnName); + } + } + + public virtual string DistributeByColumnName + { + get => GetData().ColumnName; + [param: NotNull] set + { + var (distributionStrategy, distributeByColumnFunction, _) = GetData(); + SetData(distributionStrategy, distributeByColumnFunction, value); + } + } + + private (PostgresXlDistributeByStrategy DistributionStrategy, + PostgresXlDistributeByColumnFunction DistributeByColumnFunction, + string ColumnName) GetData() + { + var str = Annotatable[AnnotationName] as string; + return str == null + ? (0, 0, null) + : Deserialize(str); + } + + private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, string ColumnName) Deserialize(string str) + { + throw new System.NotImplementedException(); + } + + private void SetData(PostgresXlDistributeByStrategy distributionStrategy, PostgresXlDistributeByColumnFunction distributeByColumnFunction, string distributeByColumnName) + { + Annotatable[AnnotationName] = Serialize(distributionStrategy, distributeByColumnFunction, distributeByColumnName); + } + + private string Serialize(PostgresXlDistributeByStrategy distributionStrategy, PostgresXlDistributeByColumnFunction distributeByColumnFunction, string distributeByColumnName) + { + throw new System.NotImplementedException(); + } + } +} diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs new file mode 100644 index 000000000..d36a55e41 --- /dev/null +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +{ + public enum PostgresXlDistributeByColumnFunction + { + None = 0, + Hash = 1, + Modulo = 2, + } +} diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs new file mode 100644 index 000000000..983acdf65 --- /dev/null +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +{ + public enum PostgresXlDistributeByStrategy + { + None = 0, + Replication = 1, + Roundrobin = 2, + Column = 3, + } +} diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index 567342c1a..c96e7e886 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -194,6 +194,18 @@ protected override void Generate( .Append(")"); } + // PostgreSQL-XL - Distribute by + if (operation[PostgresXlDistributeByAnnotationNames.DistributeBy] is string) + { + var distributeBy = new PostgresXlDistributeBy(operation); + var distributeByColumn = distributeBy.DistributeByColumnName; + builder.AppendLine() + .Append("DISTRIBUTE BY (") + .Append(distributeByColumn) + .Append(") "); + ; + } + // Comment on the table if (operation.Comment != null) { From de42146a3154da902783357a852359bb0873b356 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sun, 7 Feb 2021 18:54:34 +0000 Subject: [PATCH 02/19] Adding distribution style --- .../Metadata/PostgresXlDistributeBy.cs | 36 +- .../PostgresXlDistributeByStrategy.cs | 1 + .../Metadata/PostgresXlDistributionStyle.cs | 13 + .../NpgsqlMigrationsSqlGeneratorTest.cs | 358 ++++++++++++++++++ 4 files changed, 396 insertions(+), 12 deletions(-) create mode 100644 src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs index 339bc1ea2..64ede99ae 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs @@ -26,8 +26,8 @@ public virtual PostgresXlDistributeByStrategy DistributionStrategy get => GetData().DistributionStrategy; [param: NotNull] set { - (_, var distributeByColumnFunction, var columnName) = GetData(); - SetData(value, distributeByColumnFunction, columnName); + (_, var distributeByColumnFunction, var distributionStyle, var columnName) = GetData(); + SetData(value, distributeByColumnFunction, distributionStyle, columnName); } } @@ -36,8 +36,18 @@ public virtual PostgresXlDistributeByColumnFunction DistributeByColumnFunction get => GetData().DistributeByColumnFunction; [param: NotNull] set { - var (distributionStrategy, _, columnName) = GetData(); - SetData(distributionStrategy, value, columnName); + (var distributionStrategy, _, var distributionStyle, var columnName) = GetData(); + SetData(distributionStrategy, value, distributionStyle, columnName); + } + } + + public virtual PostgresXlDistributionStyle DistributionStyle + { + get => GetData().DistributionStyle; + [param: NotNull] set + { + (var distributionStrategy, var distributeByColumnFunction, _, var columnName) = GetData(); + SetData(distributionStrategy, distributeByColumnFunction, value, columnName); } } @@ -46,27 +56,29 @@ public virtual string DistributeByColumnName get => GetData().ColumnName; [param: NotNull] set { - var (distributionStrategy, distributeByColumnFunction, _) = GetData(); - SetData(distributionStrategy, distributeByColumnFunction, value); + (var distributionStrategy, var distributeByColumnFunction, var distributionStyle, _) = GetData(); + SetData(distributionStrategy, distributeByColumnFunction, distributionStyle, value); } } - private (PostgresXlDistributeByStrategy DistributionStrategy, - PostgresXlDistributeByColumnFunction DistributeByColumnFunction, - string ColumnName) GetData() + private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string ColumnName) GetData() { var str = Annotatable[AnnotationName] as string; return str == null - ? (0, 0, null) + ? (0, 0, 0, null) : Deserialize(str); } - private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, string ColumnName) Deserialize(string str) + private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string ColumnName) Deserialize(string str) { throw new System.NotImplementedException(); } - private void SetData(PostgresXlDistributeByStrategy distributionStrategy, PostgresXlDistributeByColumnFunction distributeByColumnFunction, string distributeByColumnName) + private void SetData( + PostgresXlDistributeByStrategy distributionStrategy, + PostgresXlDistributeByColumnFunction distributeByColumnFunction, + PostgresXlDistributionStyle postgresXlDistributionStyle, + string distributeByColumnName) { Annotatable[AnnotationName] = Serialize(distributionStrategy, distributeByColumnFunction, distributeByColumnName); } diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs index 983acdf65..22fdb1251 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs @@ -9,5 +9,6 @@ public enum PostgresXlDistributeByStrategy Replication = 1, Roundrobin = 2, Column = 3, + Randomly = 4, } } diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs b/src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs new file mode 100644 index 000000000..091fb096b --- /dev/null +++ b/src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs @@ -0,0 +1,13 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +{ + public enum PostgresXlDistributionStyle + { + None = 0, + Even = 1, + Key = 2, + All = 3, + } +} diff --git a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs index 7c011dcfb..4edb34b96 100644 --- a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs @@ -516,6 +516,364 @@ PRIMARY KEY (""Id"") #endregion CockroachDB interleave-in-parent + + #region Postgres-xl Distribute by + + // Distribute by + + [Fact] + public void CreateTableOperation_with_postgresxl_distribute_by_replication() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Replication; + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTRIBUTE BY REPLICATION; +"); + } + + [Fact] + public void CreateTableOperation_with_postgresxl_distribute_by_roundrobin() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Roundrobin; + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTRIBUTE BY ROUNDROBIN; +"); + } + + [Fact] + public void CreateTableOperation_with_postgresxl_distributed_by_hash_column() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribution.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.Hash; + distribution.DistributeByColumnName = "Id"; + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTRIBUTE BY HASH (Id); +"); + } + + [Fact] + public void CreateTableOperation_with_postgresxl_distributed_by_modulo_column() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribution.DistributeByColumnName = "Id"; + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTRIBUTE BY MODULO (Id); +"); + } + + [Fact] + public void CreateTableOperation_with_postgresxl_distributed_by_column() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribution.DistributeByColumnName = "Id"; + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTRIBUTED BY (Id); +"); + } + + [Fact] + public void CreateTableOperation_with_postgresxl_distributed_randomly() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Randomly; + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTRIBUTED RANDOMLY; +"); + } + + [Fact] + public void CreateTableOperation_with_postgresxl_diststyle_even() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStyle + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTSTYLE EVEN DISTKEY (Id); +"); + } + [Fact] + public void CreateTableOperation_with_postgresxl_diststyle_key() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTSTYLE KEY DISTKEY (Id); +"); + } + [Fact] + public void CreateTableOperation_with_postgresxl_diststyle_all() + { + var op = + new CreateTableOperation + { + Name = "People", + Schema = "dbo", + Columns = + { + new AddColumnOperation + { + Name = "Id", + Table = "People", + Schema = "dbo", + ClrType = typeof(int), + IsNullable = false + }, + }, + PrimaryKey = new AddPrimaryKeyOperation + { + Columns = new[] { "Id" } + } + }; + + var distribution = new PostgresXlDistributeBy(op); + + Generate(op); + + AssertSql( + @"CREATE TABLE dbo.""People"" ( + ""Id"" integer NOT NULL, + PRIMARY KEY (""Id"") +) +DISTSTYLE ALL DISTKEY (Id); +"); + } + + #endregion Postgres-xl Distribute by + #pragma warning disable 618 [Fact] public virtual void AddColumnOperation_serial_old_annotation_throws() From 93f5ca2e66aaa8a3625a139b1cea95255590d06b Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sun, 7 Feb 2021 21:20:57 +0000 Subject: [PATCH 03/19] implementing sql for postgresxl distribution functions --- .../Metadata/PostgresXlDistributeBy.cs | 69 +++++++++++++++++-- .../NpgsqlMigrationsSqlGenerator.cs | 57 +++++++++++++-- .../NpgsqlMigrationsSqlGeneratorTest.cs | 8 ++- 3 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs index 64ede99ae..31d3a2a34 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs @@ -1,9 +1,12 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization; +using System.Text; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.Primitives; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata @@ -69,23 +72,77 @@ public virtual string DistributeByColumnName : Deserialize(str); } - private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string ColumnName) Deserialize(string str) + private void SetData( + PostgresXlDistributeByStrategy distributionStrategy, + PostgresXlDistributeByColumnFunction distributeByColumnFunction, + PostgresXlDistributionStyle postgresXlDistributionStyle, + string distributeByColumnName) { - throw new System.NotImplementedException(); + Annotatable[AnnotationName] = Serialize(distributionStrategy, distributeByColumnFunction, postgresXlDistributionStyle, distributeByColumnName); } - private void SetData( + private string Serialize( PostgresXlDistributeByStrategy distributionStrategy, PostgresXlDistributeByColumnFunction distributeByColumnFunction, PostgresXlDistributionStyle postgresXlDistributionStyle, string distributeByColumnName) { - Annotatable[AnnotationName] = Serialize(distributionStrategy, distributeByColumnFunction, distributeByColumnName); + var stringBuilder = new StringBuilder(); + + EscapeAndQuote(stringBuilder, distributionStrategy); + stringBuilder.Append(","); + EscapeAndQuote(stringBuilder, distributeByColumnFunction); + stringBuilder.Append(","); + EscapeAndQuote(stringBuilder, postgresXlDistributionStyle); + stringBuilder.Append(","); + EscapeAndQuote(stringBuilder, distributeByColumnName); + + return stringBuilder.ToString(); + } + + private (PostgresXlDistributeByStrategy DistributionStrategy, + PostgresXlDistributeByColumnFunction DistributeByColumnFunction, + PostgresXlDistributionStyle DistributionStyle, + string ColumnName) + Deserialize(string str) + { + var position = 0; + var distributionStrategy = Enum.Parse(ExtractValue(str, ref position)); + var distributeByColumnFunction = Enum.Parse(ExtractValue(str, ref position)); + var distributionStyle = Enum.Parse(ExtractValue(str, ref position)); + var columnName = ExtractValue(str, ref position); + + return (distributionStrategy, distributeByColumnFunction, distributionStyle, columnName); } - private string Serialize(PostgresXlDistributeByStrategy distributionStrategy, PostgresXlDistributeByColumnFunction distributeByColumnFunction, string distributeByColumnName) + private static void EscapeAndQuote(StringBuilder builder, object value) { - throw new System.NotImplementedException(); + builder.Append("'"); + + if (value != null) + { + builder.Append(value.ToString().Replace("'", "''")); + } + + builder.Append("'"); + } + + private static string ExtractValue(string value, ref int position) + { + position = value.IndexOf('\'', position) + 1; + + var end = value.IndexOf('\'', position); + + while (end + 1 < value.Length + && value[end + 1] == '\'') + { + end = value.IndexOf('\'', end + 2); + } + + var extracted = value.Substring(position, end - position).Replace("''", "'"); + position = end + 1; + + return extracted.Length == 0 ? null : extracted; } } } diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index c96e7e886..58d18bc12 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -198,12 +198,59 @@ protected override void Generate( if (operation[PostgresXlDistributeByAnnotationNames.DistributeBy] is string) { var distributeBy = new PostgresXlDistributeBy(operation); + + var strategy = distributeBy.DistributionStrategy; var distributeByColumn = distributeBy.DistributeByColumnName; - builder.AppendLine() - .Append("DISTRIBUTE BY (") - .Append(distributeByColumn) - .Append(") "); - ; + var distributeByFunction = distributeBy.DistributeByColumnFunction; + var distributionStyle = distributeBy.DistributionStyle; + + if (strategy == PostgresXlDistributeByStrategy.Replication || strategy == PostgresXlDistributeByStrategy.Roundrobin || (distributeByFunction != PostgresXlDistributeByColumnFunction.None && strategy == PostgresXlDistributeByStrategy.Column)) + { + if (strategy == PostgresXlDistributeByStrategy.Replication || strategy == PostgresXlDistributeByStrategy.Roundrobin) + { + builder.AppendLine() + .Append("DISTRIBUTE BY ") + .Append(strategy.ToString().ToUpperInvariant()); + } + else if (distributeByFunction != PostgresXlDistributeByColumnFunction.None) + { + builder.AppendLine() + .Append("DISTRIBUTE BY ") + .Append(distributeByFunction.ToString().ToUpperInvariant()) + .Append(" (") + .Append(distributeByColumn) + .Append(")"); + } + } + + if (strategy == PostgresXlDistributeByStrategy.Randomly + || (strategy == PostgresXlDistributeByStrategy.Column && distributeByFunction == PostgresXlDistributeByColumnFunction.None && !string.IsNullOrWhiteSpace(distributeByColumn))) + { + builder.AppendLine() + .Append("DISTRIBUTED "); + + if (strategy == PostgresXlDistributeByStrategy.Randomly) + { + builder.Append(PostgresXlDistributeByStrategy.Randomly.ToString().ToUpperInvariant()); + } + else if (strategy == PostgresXlDistributeByStrategy.Column + && distributeByFunction == PostgresXlDistributeByColumnFunction.None) + { + builder.Append("BY (") + .Append(distributeByColumn) + .Append(")"); + } + } + + if (distributionStyle != PostgresXlDistributionStyle.None) + { + builder.AppendLine() + .Append("DISTSTYLE ") + .Append(distributionStyle.ToString().ToUpperInvariant()) + .Append(" DISTKEY (") + .Append(distributeByColumn) + .Append(")"); + } } // Comment on the table diff --git a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs index 4edb34b96..1f276a114 100644 --- a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs @@ -667,6 +667,7 @@ public void CreateTableOperation_with_postgresxl_distributed_by_modulo_column() var distribution = new PostgresXlDistributeBy(op); distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribution.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.Modulo; distribution.DistributeByColumnName = "Id"; Generate(op); @@ -785,7 +786,8 @@ public void CreateTableOperation_with_postgresxl_diststyle_even() }; var distribution = new PostgresXlDistributeBy(op); - distribution.DistributionStyle + distribution.DistributionStyle = PostgresXlDistributionStyle.Even; + distribution.DistributeByColumnName = "Id"; Generate(op); @@ -823,6 +825,8 @@ public void CreateTableOperation_with_postgresxl_diststyle_key() }; var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStyle = PostgresXlDistributionStyle.Key; + distribution.DistributeByColumnName = "Id"; Generate(op); @@ -860,6 +864,8 @@ public void CreateTableOperation_with_postgresxl_diststyle_all() }; var distribution = new PostgresXlDistributeBy(op); + distribution.DistributionStyle = PostgresXlDistributionStyle.All; + distribution.DistributeByColumnName = "Id"; Generate(op); From a6a23320b83d0ee16c39bd99616f3f86e819e708 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sun, 7 Feb 2021 22:08:55 +0000 Subject: [PATCH 04/19] Adding EntityTypeBuilderExtensions for distribute by --- .../NpgsqlEntityTypeBuilderExtensions.cs | 110 +++++++++++++++++- .../NpgsqlEntityTypeExtensions.cs | 7 ++ .../Metadata/PostgresXlDistributeBy.cs | 4 +- 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 4101228e6..6ffcc0099 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; using NpgsqlTypes; @@ -188,11 +189,13 @@ public static IConventionEntityTypeBuilder HasStorageParameter( public static bool CanSetStorageParameter( [NotNull] this IConventionEntityTypeBuilder entityTypeBuilder, [NotNull] string parameterName, - [CanBeNull] object parameterValue, bool fromDataAnnotation = false) + [CanBeNull] object parameterValue, + bool fromDataAnnotation = false) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); - return entityTypeBuilder.CanSetAnnotation(NpgsqlAnnotationNames.StorageParameterPrefix + parameterName, parameterValue, fromDataAnnotation); + return entityTypeBuilder.CanSetAnnotation( + NpgsqlAnnotationNames.StorageParameterPrefix + parameterName, parameterValue, fromDataAnnotation); } #endregion Storage parameters @@ -317,10 +320,111 @@ public static EntityTypeBuilder UseCockroachDbInterleaveInParent interleavePrefix) where TEntity : class - => (EntityTypeBuilder)UseCockroachDbInterleaveInParent((EntityTypeBuilder)entityTypeBuilder, parentTableType, interleavePrefix); + => (EntityTypeBuilder)UseCockroachDbInterleaveInParent( + (EntityTypeBuilder)entityTypeBuilder, parentTableType, interleavePrefix); #endregion CockroachDB Interleave-in-parent + #region Postgres-xl Distribute By + + + public static EntityTypeBuilder UsePostgresXlDistributedBy( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + string columnName, + PostgresXlDistributeByStrategy distributeByStrategy = PostgresXlDistributeByStrategy.Column, + PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) + + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + + var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); + switch (distributeByStrategy) + { + case PostgresXlDistributeByStrategy.Replication: + case PostgresXlDistributeByStrategy.Roundrobin: + case PostgresXlDistributeByStrategy.Randomly: + distribute.DistributionStrategy = distributeByStrategy; + + if (!string.IsNullOrWhiteSpace(columnName)) + { + throw new ArgumentException( + $"Column name \"{columnName}\" provided with a distribution strategy \"{distributeByStrategy}\" that does not require a column."); + } + + return entityTypeBuilder; + + case PostgresXlDistributeByStrategy.Column: + Check.NotEmpty(columnName, nameof(columnName)); + + distribute.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribute.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.None; + distribute.DistributeByColumnName = columnName; + + return entityTypeBuilder; + + default: + throw new ArgumentOutOfRangeException(nameof(distributeByStrategy), distributeByStrategy, $@"Invalid {nameof(PostgresXlDistributeByStrategy)} provided."); + } + } + + public static EntityTypeBuilder UsePostgresXlDistributedBy( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + string columnName, + PostgresXlDistributeByStrategy distributeByStrategy = PostgresXlDistributeByStrategy.Column, + PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) + where TEntity : class + => (EntityTypeBuilder)UsePostgresXlDistributedBy( + (EntityTypeBuilder)entityTypeBuilder, columnName, distributeByStrategy, distributeByColumnFunction); + + public static EntityTypeBuilder UsePostgresXlDistributedRandomly( + [NotNull] this EntityTypeBuilder entityTypeBuilder) + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + + var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); + distribute.DistributionStrategy = PostgresXlDistributeByStrategy.Randomly; + + return entityTypeBuilder; + } + + public static EntityTypeBuilder UsePostgresXlDistributedRandomly( + [NotNull] this EntityTypeBuilder entityTypeBuilder) + where TEntity : class + => (EntityTypeBuilder)UsePostgresXlDistributedRandomly((EntityTypeBuilder)entityTypeBuilder); + + public static EntityTypeBuilder UsePostgresXlDistributionStyle( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + PostgresXlDistributionStyle distributionStyle, + [NotNull] string distributionKey) + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + Check.NotEmpty(distributionKey, nameof(distributionKey)); + + var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); + + switch (distributionStyle) + { + case PostgresXlDistributionStyle.Even: + case PostgresXlDistributionStyle.Key: + case PostgresXlDistributionStyle.All: + distribute.DistributionStyle = distributionStyle; + distribute.DistributeByColumnName = distributionKey; + return entityTypeBuilder; + + default: + throw new ArgumentOutOfRangeException(nameof(distributionStyle), distributionStyle, $@"Invalid {nameof(PostgresXlDistributionStyle)} provided."); + } + } + + public static EntityTypeBuilder UsePostgresXlDistributionStyle( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + PostgresXlDistributionStyle distributionStyle, + [NotNull] string distributionKey) + where TEntity : class + => (EntityTypeBuilder)UsePostgresXlDistributionStyle((EntityTypeBuilder)entityTypeBuilder, distributionStyle, distributionKey); + + #endregion Postgres-xl Distribute By + #region Obsolete /// diff --git a/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs b/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs index 82a291ee2..76976e733 100644 --- a/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs +++ b/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs @@ -94,5 +94,12 @@ public static CockroachDbInterleaveInParent GetCockroachDbInterleaveInParent([No => new(entityType); #endregion CockroachDb interleave in parent + + #region Postgres-xl Distribute By + + public static PostgresXlDistributeBy GetPostgresXlDistributeBy([NotNull] this IReadOnlyEntityType entityType) + => new(entityType); + + #endregion Postgres-xl Distribute By } } diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs index 31d3a2a34..924df719f 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs @@ -21,8 +21,8 @@ public virtual Annotatable Annotatable => (Annotatable)_annotatable; - public PostgresXlDistributeBy(IAnnotatable annotatable) - => _annotatable = annotatable; + public PostgresXlDistributeBy(IReadOnlyAnnotatable annotatable) + => _annotatable = (IAnnotatable)annotatable; public virtual PostgresXlDistributeByStrategy DistributionStrategy { From 0a6e96d3cafcf1a81ff1d4c2cce90760d407e24f Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sun, 7 Feb 2021 22:49:12 +0000 Subject: [PATCH 05/19] Fixing parameter without [NotNull] --- .../NpgsqlEntityTypeBuilderExtensions.cs | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 6ffcc0099..9ef15e54f 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -327,54 +327,57 @@ public static EntityTypeBuilder UseCockroachDbInterleaveInParent UsePostgresXlDistributedBy( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + PostgresXlDistributeByStrategy distributeByStrategy) + where TEntity : class + => (EntityTypeBuilder)UsePostgresXlDistributedBy((EntityTypeBuilder)entityTypeBuilder, distributeByStrategy); - case PostgresXlDistributeByStrategy.Column: - Check.NotEmpty(columnName, nameof(columnName)); + public static EntityTypeBuilder UsePostgresXlDistributedBy( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + [NotNull] string columnName, + PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) - distribute.DistributionStrategy = PostgresXlDistributeByStrategy.Column; - distribute.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.None; - distribute.DistributeByColumnName = columnName; + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + Check.NotEmpty(columnName, nameof(columnName)); - return entityTypeBuilder; + var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); - default: - throw new ArgumentOutOfRangeException(nameof(distributeByStrategy), distributeByStrategy, $@"Invalid {nameof(PostgresXlDistributeByStrategy)} provided."); - } + distribute.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribute.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.None; + distribute.DistributeByColumnName = columnName; + + return entityTypeBuilder; } public static EntityTypeBuilder UsePostgresXlDistributedBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, string columnName, - PostgresXlDistributeByStrategy distributeByStrategy = PostgresXlDistributeByStrategy.Column, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) where TEntity : class => (EntityTypeBuilder)UsePostgresXlDistributedBy( - (EntityTypeBuilder)entityTypeBuilder, columnName, distributeByStrategy, distributeByColumnFunction); + (EntityTypeBuilder)entityTypeBuilder, columnName, distributeByColumnFunction); public static EntityTypeBuilder UsePostgresXlDistributedRandomly( [NotNull] this EntityTypeBuilder entityTypeBuilder) From 5c48e7c72067991e5fa73403967afcbd9069df4b Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sun, 7 Feb 2021 23:46:44 +0000 Subject: [PATCH 06/19] Fixing another missing [NotNull] --- .../BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 9ef15e54f..64588bd53 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -373,7 +373,7 @@ public static EntityTypeBuilder UsePostgresXlDistributedBy( public static EntityTypeBuilder UsePostgresXlDistributedBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, - string columnName, + [NotNull] string columnName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) where TEntity : class => (EntityTypeBuilder)UsePostgresXlDistributedBy( From e7c6f58534574901809bc4f3f2ff9525aee2046c Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Mon, 8 Feb 2021 23:35:29 +0000 Subject: [PATCH 07/19] Fixing failing api consistency tests due to incorrect using statement --- .../Metadata/CockroachDbInterleaveInParent.cs | 1 - .../Metadata/PostgresXlDistributeBy.cs | 19 ++++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs b/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs index bed9cb80e..a7ff24189 100644 --- a/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs +++ b/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Text; using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs index 924df719f..82dd555a7 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs @@ -1,12 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Serialization; using System.Text; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.Extensions.Primitives; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata @@ -15,19 +12,19 @@ public class PostgresXlDistributeBy { private const string AnnotationName = PostgresXlDistributeByAnnotationNames.DistributeBy; - readonly IAnnotatable _annotatable; + readonly IReadOnlyAnnotatable _annotatable; public virtual Annotatable Annotatable => (Annotatable)_annotatable; - public PostgresXlDistributeBy(IReadOnlyAnnotatable annotatable) - => _annotatable = (IAnnotatable)annotatable; + public PostgresXlDistributeBy([NotNull] IReadOnlyAnnotatable annotatable) + => _annotatable = annotatable; public virtual PostgresXlDistributeByStrategy DistributionStrategy { get => GetData().DistributionStrategy; - [param: NotNull] set + set { (_, var distributeByColumnFunction, var distributionStyle, var columnName) = GetData(); SetData(value, distributeByColumnFunction, distributionStyle, columnName); @@ -37,7 +34,7 @@ public virtual PostgresXlDistributeByStrategy DistributionStrategy public virtual PostgresXlDistributeByColumnFunction DistributeByColumnFunction { get => GetData().DistributeByColumnFunction; - [param: NotNull] set + set { (var distributionStrategy, _, var distributionStyle, var columnName) = GetData(); SetData(distributionStrategy, value, distributionStyle, columnName); @@ -47,7 +44,7 @@ public virtual PostgresXlDistributeByColumnFunction DistributeByColumnFunction public virtual PostgresXlDistributionStyle DistributionStyle { get => GetData().DistributionStyle; - [param: NotNull] set + set { (var distributionStrategy, var distributeByColumnFunction, _, var columnName) = GetData(); SetData(distributionStrategy, distributeByColumnFunction, value, columnName); @@ -57,7 +54,7 @@ public virtual PostgresXlDistributionStyle DistributionStyle public virtual string DistributeByColumnName { get => GetData().ColumnName; - [param: NotNull] set + [param:NotNull] set { (var distributionStrategy, var distributeByColumnFunction, var distributionStyle, _) = GetData(); SetData(distributionStrategy, distributeByColumnFunction, distributionStyle, value); From 822d866d44ad6499fc9e9a0d6b49563cf6a6d18e Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sat, 13 Feb 2021 13:28:26 +0000 Subject: [PATCH 08/19] Removing redundant "Column" PostgresXlDistributeByStrategy enum member --- .../NpgsqlEntityTypeBuilderExtensions.cs | 5 +- .../PostgresXlDistributeByStrategy.cs | 3 +- .../NpgsqlMigrationsSqlGenerator.cs | 72 ++++++++++--------- .../NpgsqlMigrationsSqlGeneratorTest.cs | 6 +- 4 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 64588bd53..10d9bec98 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -339,9 +339,6 @@ public static EntityTypeBuilder UsePostgresXlDistributedBy( var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); distribute.DistributionStrategy = distributeByStrategy; break; - case PostgresXlDistributeByStrategy.Column: - throw new ArgumentException( - $"PostgresXl distribution strategy {nameof(PostgresXlDistributeByStrategy.Column)} provided without a column name."); } return entityTypeBuilder; @@ -364,7 +361,7 @@ public static EntityTypeBuilder UsePostgresXlDistributedBy( var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); - distribute.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribute.DistributionStrategy = PostgresXlDistributeByStrategy.None; distribute.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.None; distribute.DistributeByColumnName = columnName; diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs index 22fdb1251..b17bbcfe6 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs @@ -8,7 +8,6 @@ public enum PostgresXlDistributeByStrategy None = 0, Replication = 1, Roundrobin = 2, - Column = 3, - Randomly = 4, + Randomly = 3, } } diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index 58d18bc12..acd44fd00 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -194,7 +194,7 @@ protected override void Generate( .Append(")"); } - // PostgreSQL-XL - Distribute by + // PostgreSQL-XL - Distribute by (https://www.postgres-xl.org/documentation/sql-createtable.html) if (operation[PostgresXlDistributeByAnnotationNames.DistributeBy] is string) { var distributeBy = new PostgresXlDistributeBy(operation); @@ -204,45 +204,53 @@ protected override void Generate( var distributeByFunction = distributeBy.DistributeByColumnFunction; var distributionStyle = distributeBy.DistributionStyle; - if (strategy == PostgresXlDistributeByStrategy.Replication || strategy == PostgresXlDistributeByStrategy.Roundrobin || (distributeByFunction != PostgresXlDistributeByColumnFunction.None && strategy == PostgresXlDistributeByStrategy.Column)) + if (distributionStyle == PostgresXlDistributionStyle.None) { - if (strategy == PostgresXlDistributeByStrategy.Replication || strategy == PostgresXlDistributeByStrategy.Roundrobin) + if (strategy == PostgresXlDistributeByStrategy.Replication + || strategy == PostgresXlDistributeByStrategy.Roundrobin + || (distributeByFunction != PostgresXlDistributeByColumnFunction.None + && !string.IsNullOrWhiteSpace(distributeByColumn))) { - builder.AppendLine() - .Append("DISTRIBUTE BY ") - .Append(strategy.ToString().ToUpperInvariant()); - } - else if (distributeByFunction != PostgresXlDistributeByColumnFunction.None) - { - builder.AppendLine() - .Append("DISTRIBUTE BY ") - .Append(distributeByFunction.ToString().ToUpperInvariant()) - .Append(" (") - .Append(distributeByColumn) - .Append(")"); + if (strategy == PostgresXlDistributeByStrategy.Replication || strategy == PostgresXlDistributeByStrategy.Roundrobin) + { + builder.AppendLine() + .Append("DISTRIBUTE BY ") + .Append(strategy.ToString().ToUpperInvariant()); + } + else if (distributeByFunction != PostgresXlDistributeByColumnFunction.None) + { + builder.AppendLine() + .Append("DISTRIBUTE BY ") + .Append(distributeByFunction.ToString().ToUpperInvariant()) + .Append(" (") + .Append(distributeByColumn) + .Append(")"); + } } - } - if (strategy == PostgresXlDistributeByStrategy.Randomly - || (strategy == PostgresXlDistributeByStrategy.Column && distributeByFunction == PostgresXlDistributeByColumnFunction.None && !string.IsNullOrWhiteSpace(distributeByColumn))) - { - builder.AppendLine() - .Append("DISTRIBUTED "); - if (strategy == PostgresXlDistributeByStrategy.Randomly) + if ((strategy == PostgresXlDistributeByStrategy.Randomly + || (distributeByFunction == PostgresXlDistributeByColumnFunction.None + && !string.IsNullOrWhiteSpace(distributeByColumn))) + ) { - builder.Append(PostgresXlDistributeByStrategy.Randomly.ToString().ToUpperInvariant()); - } - else if (strategy == PostgresXlDistributeByStrategy.Column - && distributeByFunction == PostgresXlDistributeByColumnFunction.None) - { - builder.Append("BY (") - .Append(distributeByColumn) - .Append(")"); + builder.AppendLine() + .Append("DISTRIBUTED "); + + if (strategy == PostgresXlDistributeByStrategy.Randomly) + { + builder.Append(PostgresXlDistributeByStrategy.Randomly.ToString().ToUpperInvariant()); + } + else if (!string.IsNullOrWhiteSpace(distributeByColumn) + && distributeByFunction == PostgresXlDistributeByColumnFunction.None) + { + builder.Append("BY (") + .Append(distributeByColumn) + .Append(")"); + } } } - - if (distributionStyle != PostgresXlDistributionStyle.None) + else { builder.AppendLine() .Append("DISTSTYLE ") diff --git a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs index 1f276a114..a3e4c6f44 100644 --- a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs @@ -625,7 +625,7 @@ public void CreateTableOperation_with_postgresxl_distributed_by_hash_column() }; var distribution = new PostgresXlDistributeBy(op); - distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.None; distribution.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.Hash; distribution.DistributeByColumnName = "Id"; @@ -666,7 +666,7 @@ public void CreateTableOperation_with_postgresxl_distributed_by_modulo_column() }; var distribution = new PostgresXlDistributeBy(op); - distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.None; distribution.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.Modulo; distribution.DistributeByColumnName = "Id"; @@ -707,7 +707,7 @@ public void CreateTableOperation_with_postgresxl_distributed_by_column() }; var distribution = new PostgresXlDistributeBy(op); - distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Column; + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.None; distribution.DistributeByColumnName = "Id"; Generate(op); From e523a958d27852f5d05e560c55416df503159338 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sat, 13 Feb 2021 13:47:04 +0000 Subject: [PATCH 09/19] Undoing accidental formatting changes --- .../NpgsqlEntityTypeBuilderExtensions.cs | 9 +++------ src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 10d9bec98..94038b157 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -189,13 +189,11 @@ public static IConventionEntityTypeBuilder HasStorageParameter( public static bool CanSetStorageParameter( [NotNull] this IConventionEntityTypeBuilder entityTypeBuilder, [NotNull] string parameterName, - [CanBeNull] object parameterValue, - bool fromDataAnnotation = false) + [CanBeNull] object parameterValue, bool fromDataAnnotation = false) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); - return entityTypeBuilder.CanSetAnnotation( - NpgsqlAnnotationNames.StorageParameterPrefix + parameterName, parameterValue, fromDataAnnotation); + return entityTypeBuilder.CanSetAnnotation(NpgsqlAnnotationNames.StorageParameterPrefix + parameterName, parameterValue, fromDataAnnotation); } #endregion Storage parameters @@ -320,8 +318,7 @@ public static EntityTypeBuilder UseCockroachDbInterleaveInParent interleavePrefix) where TEntity : class - => (EntityTypeBuilder)UseCockroachDbInterleaveInParent( - (EntityTypeBuilder)entityTypeBuilder, parentTableType, interleavePrefix); + => (EntityTypeBuilder)UseCockroachDbInterleaveInParent((EntityTypeBuilder)entityTypeBuilder, parentTableType, interleavePrefix); #endregion CockroachDB Interleave-in-parent diff --git a/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs b/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs index a7ff24189..bed9cb80e 100644 --- a/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs +++ b/src/EFCore.PG/Metadata/CockroachDbInterleaveInParent.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; From e687815a86969acfa91b4f45a2e6e2e3b02e8e6d Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sat, 27 Feb 2021 14:35:38 +0000 Subject: [PATCH 10/19] tidying up test names and fixing diststyle --- .../NpgsqlEntityTypeBuilderExtensions.cs | 12 ++++++------ .../Migrations/NpgsqlMigrationsSqlGenerator.cs | 8 +++++++- .../Migrations/NpgsqlMigrationsSqlGeneratorTest.cs | 10 ++++------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 94038b157..ca7e4809d 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -324,7 +324,7 @@ public static EntityTypeBuilder UseCockroachDbInterleaveInParent UsePostgresXlDistributedBy( + public static EntityTypeBuilder UsePostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, PostgresXlDistributeByStrategy distributeByStrategy) where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributedBy((EntityTypeBuilder)entityTypeBuilder, distributeByStrategy); + => (EntityTypeBuilder)UsePostgresXlDistributeBy((EntityTypeBuilder)entityTypeBuilder, distributeByStrategy); - public static EntityTypeBuilder UsePostgresXlDistributedBy( + public static EntityTypeBuilder UsePostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string columnName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) @@ -365,12 +365,12 @@ public static EntityTypeBuilder UsePostgresXlDistributedBy( return entityTypeBuilder; } - public static EntityTypeBuilder UsePostgresXlDistributedBy( + public static EntityTypeBuilder UsePostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string columnName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributedBy( + => (EntityTypeBuilder)UsePostgresXlDistributeBy( (EntityTypeBuilder)entityTypeBuilder, columnName, distributeByColumnFunction); public static EntityTypeBuilder UsePostgresXlDistributedRandomly( diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index acd44fd00..13d201e03 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -250,7 +250,7 @@ protected override void Generate( } } } - else + else if (distributionStyle == PostgresXlDistributionStyle.Key) { builder.AppendLine() .Append("DISTSTYLE ") @@ -259,6 +259,12 @@ protected override void Generate( .Append(distributeByColumn) .Append(")"); } + else if (distributionStyle == PostgresXlDistributionStyle.All || distributionStyle == PostgresXlDistributionStyle.Even) + { + builder.AppendLine() + .Append("DISTSTYLE ") + .Append(distributionStyle.ToString().ToUpperInvariant()); + } } // Comment on the table diff --git a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs index a3e4c6f44..985a19a8b 100644 --- a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs @@ -600,7 +600,7 @@ PRIMARY KEY (""Id"") } [Fact] - public void CreateTableOperation_with_postgresxl_distributed_by_hash_column() + public void CreateTableOperation_with_postgresxl_distribute_by_hash_column() { var op = new CreateTableOperation @@ -641,7 +641,7 @@ PRIMARY KEY (""Id"") } [Fact] - public void CreateTableOperation_with_postgresxl_distributed_by_modulo_column() + public void CreateTableOperation_with_postgresxl_distribute_by_modulo_column() { var op = new CreateTableOperation @@ -787,7 +787,6 @@ public void CreateTableOperation_with_postgresxl_diststyle_even() var distribution = new PostgresXlDistributeBy(op); distribution.DistributionStyle = PostgresXlDistributionStyle.Even; - distribution.DistributeByColumnName = "Id"; Generate(op); @@ -796,7 +795,7 @@ public void CreateTableOperation_with_postgresxl_diststyle_even() ""Id"" integer NOT NULL, PRIMARY KEY (""Id"") ) -DISTSTYLE EVEN DISTKEY (Id); +DISTSTYLE EVEN; "); } [Fact] @@ -865,7 +864,6 @@ public void CreateTableOperation_with_postgresxl_diststyle_all() var distribution = new PostgresXlDistributeBy(op); distribution.DistributionStyle = PostgresXlDistributionStyle.All; - distribution.DistributeByColumnName = "Id"; Generate(op); @@ -874,7 +872,7 @@ public void CreateTableOperation_with_postgresxl_diststyle_all() ""Id"" integer NOT NULL, PRIMARY KEY (""Id"") ) -DISTSTYLE ALL DISTKEY (Id); +DISTSTYLE ALL; "); } From ee878479f547e4a6e395fb4228744c696029508d Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sat, 27 Feb 2021 15:31:48 +0000 Subject: [PATCH 11/19] Adding validation for distribution properties --- .../NpgsqlMigrationsSqlGenerator.cs | 154 +++++++++++++++--- 1 file changed, 134 insertions(+), 20 deletions(-) diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index 13d201e03..c78fd6b7d 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -199,53 +199,55 @@ protected override void Generate( { var distributeBy = new PostgresXlDistributeBy(operation); - var strategy = distributeBy.DistributionStrategy; - var distributeByColumn = distributeBy.DistributeByColumnName; - var distributeByFunction = distributeBy.DistributeByColumnFunction; + var distributionStrategy = distributeBy.DistributionStrategy; + var distributeByColumnFunction = distributeBy.DistributeByColumnFunction; var distributionStyle = distributeBy.DistributionStyle; + var distributeByColumnName = distributeBy.DistributeByColumnName; + + ValidateTableDistributionProperties(distributionStrategy, distributeByColumnFunction, distributionStyle, distributeByColumnName); if (distributionStyle == PostgresXlDistributionStyle.None) { - if (strategy == PostgresXlDistributeByStrategy.Replication - || strategy == PostgresXlDistributeByStrategy.Roundrobin - || (distributeByFunction != PostgresXlDistributeByColumnFunction.None - && !string.IsNullOrWhiteSpace(distributeByColumn))) + if (distributionStrategy == PostgresXlDistributeByStrategy.Replication + || distributionStrategy == PostgresXlDistributeByStrategy.Roundrobin + || (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None + && !string.IsNullOrWhiteSpace(distributeByColumnName))) { - if (strategy == PostgresXlDistributeByStrategy.Replication || strategy == PostgresXlDistributeByStrategy.Roundrobin) + if (distributionStrategy == PostgresXlDistributeByStrategy.Replication || distributionStrategy == PostgresXlDistributeByStrategy.Roundrobin) { builder.AppendLine() .Append("DISTRIBUTE BY ") - .Append(strategy.ToString().ToUpperInvariant()); + .Append(distributionStrategy.ToString().ToUpperInvariant()); } - else if (distributeByFunction != PostgresXlDistributeByColumnFunction.None) + else if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) { builder.AppendLine() .Append("DISTRIBUTE BY ") - .Append(distributeByFunction.ToString().ToUpperInvariant()) + .Append(distributeByColumnFunction.ToString().ToUpperInvariant()) .Append(" (") - .Append(distributeByColumn) + .Append(distributeByColumnName) .Append(")"); } } - if ((strategy == PostgresXlDistributeByStrategy.Randomly - || (distributeByFunction == PostgresXlDistributeByColumnFunction.None - && !string.IsNullOrWhiteSpace(distributeByColumn))) + if ((distributionStrategy == PostgresXlDistributeByStrategy.Randomly + || (distributeByColumnFunction == PostgresXlDistributeByColumnFunction.None + && !string.IsNullOrWhiteSpace(distributeByColumnName))) ) { builder.AppendLine() .Append("DISTRIBUTED "); - if (strategy == PostgresXlDistributeByStrategy.Randomly) + if (distributionStrategy == PostgresXlDistributeByStrategy.Randomly) { builder.Append(PostgresXlDistributeByStrategy.Randomly.ToString().ToUpperInvariant()); } - else if (!string.IsNullOrWhiteSpace(distributeByColumn) - && distributeByFunction == PostgresXlDistributeByColumnFunction.None) + else if (!string.IsNullOrWhiteSpace(distributeByColumnName) + && distributeByColumnFunction == PostgresXlDistributeByColumnFunction.None) { builder.Append("BY (") - .Append(distributeByColumn) + .Append(distributeByColumnName) .Append(")"); } } @@ -256,7 +258,7 @@ protected override void Generate( .Append("DISTSTYLE ") .Append(distributionStyle.ToString().ToUpperInvariant()) .Append(" DISTKEY (") - .Append(distributeByColumn) + .Append(distributeByColumnName) .Append(")"); } else if (distributionStyle == PostgresXlDistributionStyle.All || distributionStyle == PostgresXlDistributionStyle.Even) @@ -1894,6 +1896,118 @@ public IndexColumn(string name, string @operator, string collation, SortOrder so public NullSortOrder NullSortOrder { get; } } + private static void ValidateTableDistributionProperties( + PostgresXlDistributeByStrategy distributionStrategy, + PostgresXlDistributeByColumnFunction distributeByColumnFunction, + PostgresXlDistributionStyle distributionStyle, + string distributeByColumnName) + { + switch (distributionStrategy) + { + case PostgresXlDistributeByStrategy.Replication: + case PostgresXlDistributeByStrategy.Roundrobin: + case PostgresXlDistributeByStrategy.Randomly: + // If column is defined, throw + if (!string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); + } + + // If any others are defined, throw + if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); + } + + if (distributionStyle != PostgresXlDistributionStyle.None) + { + throw new NotSupportedException( + $"{nameof(distributionStyle)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); + } + + break; + } + + switch (distributeByColumnFunction) + { + case PostgresXlDistributeByColumnFunction.Hash: + case PostgresXlDistributeByColumnFunction.Modulo: + // If column is not defined, throw + if (string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); + } + + // If any others are defined, throw + if (distributionStrategy != PostgresXlDistributeByStrategy.None) + { + throw new NotSupportedException( + $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); + } + + if (distributionStyle != PostgresXlDistributionStyle.None) + { + throw new NotSupportedException( + $"{nameof(distributionStyle)} cannot be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); + } + + break; + } + + switch (distributionStyle) + { + case PostgresXlDistributionStyle.Key: + // If column is not defined, throw + if (string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + // If any others are defined, throw + if (distributionStrategy != PostgresXlDistributeByStrategy.None) + { + throw new NotSupportedException( + $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + break; + case PostgresXlDistributionStyle.Even: + case PostgresXlDistributionStyle.All: + // If column is defined, throw + if (!string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + // If any others are defined, throw + if (distributionStrategy != PostgresXlDistributeByStrategy.None) + { + throw new NotSupportedException( + $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + // If any others are defined, throw + break; + } + } + #endregion } } From 281a717def3ad0de494faaba949dc939716961bc Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sat, 27 Feb 2021 16:55:43 +0000 Subject: [PATCH 12/19] Diststyle key tweaks --- .../NpgsqlEntityTypeBuilderExtensions.cs | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index ca7e4809d..df27d4de6 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -391,23 +391,21 @@ public static EntityTypeBuilder UsePostgresXlDistributedRandomly UsePostgresXlDistributionStyle( [NotNull] this EntityTypeBuilder entityTypeBuilder, - PostgresXlDistributionStyle distributionStyle, + PostgresXlDistributionStyle distributionStyle + ) + where TEntity : class + => (EntityTypeBuilder)UsePostgresXlDistributionStyle((EntityTypeBuilder)entityTypeBuilder, distributionStyle); + + + public static EntityTypeBuilder UsePostgresXlDistributionStyleKey( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + [NotNull] string distributionKey) + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + Check.NotEmpty(distributionKey, nameof(distributionKey)); + + var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); + + distribute.DistributionStyle = PostgresXlDistributionStyle.Key; + distribute.DistributeByColumnName = distributionKey; + return entityTypeBuilder; + } + + public static EntityTypeBuilder UsePostgresXlDistributionStyleKey( + [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string distributionKey) where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributionStyle((EntityTypeBuilder)entityTypeBuilder, distributionStyle, distributionKey); + => (EntityTypeBuilder)UsePostgresXlDistributionStyleKey((EntityTypeBuilder)entityTypeBuilder, distributionKey); #endregion Postgres-xl Distribute By From 9c6f6a85c282b57517daee0a8cd4bbfbf53701d9 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sat, 27 Feb 2021 18:03:39 +0000 Subject: [PATCH 13/19] tidying up and pr comments --- .../NpgsqlEntityTypeBuilderExtensions.cs | 55 +++++++------------ .../{ => Internal}/PostgresXlDistributeBy.cs | 26 ++++++--- .../PostgresXlDistributeByAnnotationNames.cs | 2 - .../PostgresXlDistributeByColumnFunction.cs | 3 +- .../PostgresXlDistributeByStrategy.cs | 5 +- .../Metadata/PostgresXlDistributionStyle.cs | 3 +- .../NpgsqlMigrationsSqlGenerator.cs | 46 ++++++---------- .../NpgsqlMigrationsSqlGeneratorTest.cs | 5 +- 8 files changed, 62 insertions(+), 83 deletions(-) rename src/EFCore.PG/Metadata/{ => Internal}/PostgresXlDistributeBy.cs (83%) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index df27d4de6..01ae81221 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -6,7 +6,6 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; using Npgsql.EntityFrameworkCore.PostgreSQL.Utilities; using NpgsqlTypes; @@ -324,14 +323,14 @@ public static EntityTypeBuilder UseCockroachDbInterleaveInParent UsePostgresXlDistributeBy( + public static EntityTypeBuilder PostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, PostgresXlDistributeByStrategy distributeByStrategy) where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributeBy((EntityTypeBuilder)entityTypeBuilder, distributeByStrategy); + => (EntityTypeBuilder)PostgresXlDistributeBy((EntityTypeBuilder)entityTypeBuilder, distributeByStrategy); - public static EntityTypeBuilder UsePostgresXlDistributeBy( + public static EntityTypeBuilder PostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string columnName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) @@ -365,31 +364,15 @@ public static EntityTypeBuilder UsePostgresXlDistributeBy( return entityTypeBuilder; } - public static EntityTypeBuilder UsePostgresXlDistributeBy( + public static EntityTypeBuilder PostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string columnName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributeBy( + => (EntityTypeBuilder)PostgresXlDistributeBy( (EntityTypeBuilder)entityTypeBuilder, columnName, distributeByColumnFunction); - public static EntityTypeBuilder UsePostgresXlDistributedRandomly( - [NotNull] this EntityTypeBuilder entityTypeBuilder) - { - Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); - - var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); - distribute.DistributionStrategy = PostgresXlDistributeByStrategy.Randomly; - - return entityTypeBuilder; - } - - public static EntityTypeBuilder UsePostgresXlDistributedRandomly( - [NotNull] this EntityTypeBuilder entityTypeBuilder) - where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributedRandomly((EntityTypeBuilder)entityTypeBuilder); - - public static EntityTypeBuilder UsePostgresXlDistributionStyle( + public static EntityTypeBuilder PostgresXlDistributionStyle( [NotNull] this EntityTypeBuilder entityTypeBuilder, PostgresXlDistributionStyle distributionStyle) { @@ -399,27 +382,27 @@ public static EntityTypeBuilder UsePostgresXlDistributionStyle( switch (distributionStyle) { - case PostgresXlDistributionStyle.Even: - case PostgresXlDistributionStyle.All: + case EntityFrameworkCore.PostgresXlDistributionStyle.Even: + case EntityFrameworkCore.PostgresXlDistributionStyle.All: distribute.DistributionStyle = distributionStyle; return entityTypeBuilder; - case PostgresXlDistributionStyle.Key: + case EntityFrameworkCore.PostgresXlDistributionStyle.Key: throw new ArgumentException( - $"Distribution style {PostgresXlDistributionStyle.Key} was provided with no key. To use DISTSTYLE KEY, use {nameof(UsePostgresXlDistributionStyleKey)} instead."); + $"Distribution style {EntityFrameworkCore.PostgresXlDistributionStyle.Key} was provided with no key. To use DISTSTYLE KEY, use {nameof(PostgresXlDistributionStyleKey)} instead."); default: - throw new ArgumentOutOfRangeException(nameof(distributionStyle), distributionStyle, $@"Invalid {nameof(PostgresXlDistributionStyle)} provided."); + throw new ArgumentOutOfRangeException(nameof(distributionStyle), distributionStyle, $@"Invalid {nameof(EntityFrameworkCore)} provided."); } } - public static EntityTypeBuilder UsePostgresXlDistributionStyle( + public static EntityTypeBuilder PostgresXlDistributionStyle( [NotNull] this EntityTypeBuilder entityTypeBuilder, PostgresXlDistributionStyle distributionStyle ) where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributionStyle((EntityTypeBuilder)entityTypeBuilder, distributionStyle); + => (EntityTypeBuilder)PostgresXlDistributionStyle((EntityTypeBuilder)entityTypeBuilder, distributionStyle); - public static EntityTypeBuilder UsePostgresXlDistributionStyleKey( + public static EntityTypeBuilder PostgresXlDistributionStyleKey( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string distributionKey) { @@ -428,16 +411,16 @@ public static EntityTypeBuilder UsePostgresXlDistributionStyleKey( var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); - distribute.DistributionStyle = PostgresXlDistributionStyle.Key; + distribute.DistributionStyle = EntityFrameworkCore.PostgresXlDistributionStyle.Key; distribute.DistributeByColumnName = distributionKey; return entityTypeBuilder; } - public static EntityTypeBuilder UsePostgresXlDistributionStyleKey( + public static EntityTypeBuilder PostgresXlDistributionStyleKey( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string distributionKey) where TEntity : class - => (EntityTypeBuilder)UsePostgresXlDistributionStyleKey((EntityTypeBuilder)entityTypeBuilder, distributionKey); + => (EntityTypeBuilder)PostgresXlDistributionStyleKey((EntityTypeBuilder)entityTypeBuilder, distributionKey); #endregion Postgres-xl Distribute By diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs similarity index 83% rename from src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs rename to src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs index 82dd555a7..64ba09210 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs @@ -1,23 +1,23 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System; using System.Text; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal; -namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal { public class PostgresXlDistributeBy { private const string AnnotationName = PostgresXlDistributeByAnnotationNames.DistributeBy; - readonly IReadOnlyAnnotatable _annotatable; + private readonly IReadOnlyAnnotatable _annotatable; public virtual Annotatable Annotatable => (Annotatable)_annotatable; - public PostgresXlDistributeBy([NotNull] IReadOnlyAnnotatable annotatable) => _annotatable = annotatable; @@ -26,7 +26,7 @@ public virtual PostgresXlDistributeByStrategy DistributionStrategy get => GetData().DistributionStrategy; set { - (_, var distributeByColumnFunction, var distributionStyle, var columnName) = GetData(); + var (_, distributeByColumnFunction, distributionStyle, columnName) = GetData(); SetData(value, distributeByColumnFunction, distributionStyle, columnName); } } @@ -36,7 +36,7 @@ public virtual PostgresXlDistributeByColumnFunction DistributeByColumnFunction get => GetData().DistributeByColumnFunction; set { - (var distributionStrategy, _, var distributionStyle, var columnName) = GetData(); + var (distributionStrategy, _, distributionStyle, columnName) = GetData(); SetData(distributionStrategy, value, distributionStyle, columnName); } } @@ -46,7 +46,7 @@ public virtual PostgresXlDistributionStyle DistributionStyle get => GetData().DistributionStyle; set { - (var distributionStrategy, var distributeByColumnFunction, _, var columnName) = GetData(); + var (distributionStrategy, distributeByColumnFunction, _, columnName) = GetData(); SetData(distributionStrategy, distributeByColumnFunction, value, columnName); } } @@ -56,11 +56,21 @@ public virtual string DistributeByColumnName get => GetData().ColumnName; [param:NotNull] set { - (var distributionStrategy, var distributeByColumnFunction, var distributionStyle, _) = GetData(); + var (distributionStrategy, distributeByColumnFunction, distributionStyle, _) = GetData(); SetData(distributionStrategy, distributeByColumnFunction, distributionStyle, value); } } + public virtual (PostgresXlDistributeByStrategy distributionStrategy, + PostgresXlDistributeByColumnFunction distributeByColumnFunction, + PostgresXlDistributionStyle distributionStyle, + string distributeByColumnName) Deconstruct() + => ( + DistributionStrategy, + DistributeByColumnFunction, + DistributionStyle, + DistributeByColumnName); + private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string ColumnName) GetData() { var str = Annotatable[AnnotationName] as string; diff --git a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs index d0029d30a..7c2b8bb24 100644 --- a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs +++ b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeByAnnotationNames.cs @@ -5,10 +5,8 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal { internal static class PostgresXlDistributeByAnnotationNames { - public const string Prefix = NpgsqlAnnotationNames.Prefix + "PostgresXL:"; public const string DistributeBy = Prefix + "DistributeBy"; - } } diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs index d36a55e41..8292f0f64 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeByColumnFunction.cs @@ -1,7 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +// ReSharper disable once CheckNamespace +namespace Microsoft.EntityFrameworkCore { public enum PostgresXlDistributeByColumnFunction { diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs index b17bbcfe6..550a926f1 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributeByStrategy.cs @@ -1,13 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +// ReSharper disable once CheckNamespace +namespace Microsoft.EntityFrameworkCore { public enum PostgresXlDistributeByStrategy { None = 0, Replication = 1, - Roundrobin = 2, + RoundRobin = 2, Randomly = 3, } } diff --git a/src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs b/src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs index 091fb096b..9e2460132 100644 --- a/src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs +++ b/src/EFCore.PG/Metadata/PostgresXlDistributionStyle.cs @@ -1,7 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Npgsql.EntityFrameworkCore.PostgreSQL.Metadata +// ReSharper disable once CheckNamespace +namespace Microsoft.EntityFrameworkCore { public enum PostgresXlDistributionStyle { diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index c78fd6b7d..a37507f0b 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -194,47 +194,35 @@ protected override void Generate( .Append(")"); } - // PostgreSQL-XL - Distribute by (https://www.postgres-xl.org/documentation/sql-createtable.html) + // Postgres-XL - Distribute by (https://www.postgres-xl.org/documentation/sql-createtable.html) if (operation[PostgresXlDistributeByAnnotationNames.DistributeBy] is string) { var distributeBy = new PostgresXlDistributeBy(operation); - - var distributionStrategy = distributeBy.DistributionStrategy; - var distributeByColumnFunction = distributeBy.DistributeByColumnFunction; - var distributionStyle = distributeBy.DistributionStyle; - var distributeByColumnName = distributeBy.DistributeByColumnName; + var (distributionStrategy, distributeByColumnFunction, distributionStyle, distributeByColumnName) = distributeBy.Deconstruct(); ValidateTableDistributionProperties(distributionStrategy, distributeByColumnFunction, distributionStyle, distributeByColumnName); if (distributionStyle == PostgresXlDistributionStyle.None) { - if (distributionStrategy == PostgresXlDistributeByStrategy.Replication - || distributionStrategy == PostgresXlDistributeByStrategy.Roundrobin - || (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None - && !string.IsNullOrWhiteSpace(distributeByColumnName))) + if (distributionStrategy == PostgresXlDistributeByStrategy.Replication || distributionStrategy == PostgresXlDistributeByStrategy.RoundRobin) { - if (distributionStrategy == PostgresXlDistributeByStrategy.Replication || distributionStrategy == PostgresXlDistributeByStrategy.Roundrobin) - { - builder.AppendLine() - .Append("DISTRIBUTE BY ") - .Append(distributionStrategy.ToString().ToUpperInvariant()); - } - else if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) - { - builder.AppendLine() - .Append("DISTRIBUTE BY ") - .Append(distributeByColumnFunction.ToString().ToUpperInvariant()) - .Append(" (") - .Append(distributeByColumnName) - .Append(")"); - } + builder.AppendLine() + .Append("DISTRIBUTE BY ") + .Append(distributionStrategy.ToString().ToUpperInvariant()); + } + else if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) + { + builder.AppendLine() + .Append("DISTRIBUTE BY ") + .Append(distributeByColumnFunction.ToString().ToUpperInvariant()) + .Append(" (") + .Append(distributeByColumnName) + .Append(")"); } - if ((distributionStrategy == PostgresXlDistributeByStrategy.Randomly || (distributeByColumnFunction == PostgresXlDistributeByColumnFunction.None - && !string.IsNullOrWhiteSpace(distributeByColumnName))) - ) + && !string.IsNullOrWhiteSpace(distributeByColumnName)))) { builder.AppendLine() .Append("DISTRIBUTED "); @@ -1905,7 +1893,7 @@ private static void ValidateTableDistributionProperties( switch (distributionStrategy) { case PostgresXlDistributeByStrategy.Replication: - case PostgresXlDistributeByStrategy.Roundrobin: + case PostgresXlDistributeByStrategy.RoundRobin: case PostgresXlDistributeByStrategy.Randomly: // If column is defined, throw if (!string.IsNullOrWhiteSpace(distributeByColumnName)) diff --git a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs index 985a19a8b..6e003f9ae 100644 --- a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs @@ -516,11 +516,8 @@ PRIMARY KEY (""Id"") #endregion CockroachDB interleave-in-parent - #region Postgres-xl Distribute by - // Distribute by - [Fact] public void CreateTableOperation_with_postgresxl_distribute_by_replication() { @@ -586,7 +583,7 @@ public void CreateTableOperation_with_postgresxl_distribute_by_roundrobin() }; var distribution = new PostgresXlDistributeBy(op); - distribution.DistributionStrategy = PostgresXlDistributeByStrategy.Roundrobin; + distribution.DistributionStrategy = PostgresXlDistributeByStrategy.RoundRobin; Generate(op); From 7d88298a77229395c5e04c3227bee57805a80e11 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Sun, 28 Feb 2021 18:59:00 +0000 Subject: [PATCH 14/19] Variable names and delimiting --- .../NpgsqlEntityTypeBuilderExtensions.cs | 12 ++++++------ .../Metadata/Internal/PostgresXlDistributeBy.cs | 4 ++-- .../Migrations/NpgsqlMigrationsSqlGenerator.cs | 6 +++--- .../NpgsqlMigrationsSqlGeneratorTest.cs | 16 ++++++++-------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 01ae81221..dec5db48c 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -348,29 +348,29 @@ public static EntityTypeBuilder PostgresXlDistributeBy( public static EntityTypeBuilder PostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] string columnName, + [NotNull] string propertyName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); - Check.NotEmpty(columnName, nameof(columnName)); + Check.NotEmpty(propertyName, nameof(propertyName)); var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); distribute.DistributionStrategy = PostgresXlDistributeByStrategy.None; distribute.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.None; - distribute.DistributeByColumnName = columnName; + distribute.DistributeByPropertyName = propertyName; return entityTypeBuilder; } public static EntityTypeBuilder PostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] string columnName, + [NotNull] string propertyName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) where TEntity : class => (EntityTypeBuilder)PostgresXlDistributeBy( - (EntityTypeBuilder)entityTypeBuilder, columnName, distributeByColumnFunction); + (EntityTypeBuilder)entityTypeBuilder, propertyName, distributeByColumnFunction); public static EntityTypeBuilder PostgresXlDistributionStyle( [NotNull] this EntityTypeBuilder entityTypeBuilder, @@ -412,7 +412,7 @@ public static EntityTypeBuilder PostgresXlDistributionStyleKey( var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); distribute.DistributionStyle = EntityFrameworkCore.PostgresXlDistributionStyle.Key; - distribute.DistributeByColumnName = distributionKey; + distribute.DistributeByPropertyName = distributionKey; return entityTypeBuilder; } diff --git a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs index 64ba09210..62dbb3954 100644 --- a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs @@ -51,7 +51,7 @@ public virtual PostgresXlDistributionStyle DistributionStyle } } - public virtual string DistributeByColumnName + public virtual string DistributeByPropertyName { get => GetData().ColumnName; [param:NotNull] set @@ -69,7 +69,7 @@ public virtual (PostgresXlDistributeByStrategy distributionStrategy, DistributionStrategy, DistributeByColumnFunction, DistributionStyle, - DistributeByColumnName); + DistributeByPropertyName); private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string ColumnName) GetData() { diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index a37507f0b..c29300465 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -216,7 +216,7 @@ protected override void Generate( .Append("DISTRIBUTE BY ") .Append(distributeByColumnFunction.ToString().ToUpperInvariant()) .Append(" (") - .Append(distributeByColumnName) + .Append(DelimitIdentifier(distributeByColumnName)) .Append(")"); } @@ -235,7 +235,7 @@ protected override void Generate( && distributeByColumnFunction == PostgresXlDistributeByColumnFunction.None) { builder.Append("BY (") - .Append(distributeByColumnName) + .Append(DelimitIdentifier(distributeByColumnName)) .Append(")"); } } @@ -246,7 +246,7 @@ protected override void Generate( .Append("DISTSTYLE ") .Append(distributionStyle.ToString().ToUpperInvariant()) .Append(" DISTKEY (") - .Append(distributeByColumnName) + .Append(DelimitIdentifier(distributeByColumnName)) .Append(")"); } else if (distributionStyle == PostgresXlDistributionStyle.All || distributionStyle == PostgresXlDistributionStyle.Even) diff --git a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs index 6e003f9ae..d6b3225a8 100644 --- a/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.PG.FunctionalTests/Migrations/NpgsqlMigrationsSqlGeneratorTest.cs @@ -624,7 +624,7 @@ public void CreateTableOperation_with_postgresxl_distribute_by_hash_column() var distribution = new PostgresXlDistributeBy(op); distribution.DistributionStrategy = PostgresXlDistributeByStrategy.None; distribution.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.Hash; - distribution.DistributeByColumnName = "Id"; + distribution.DistributeByPropertyName = "Id"; Generate(op); @@ -633,7 +633,7 @@ public void CreateTableOperation_with_postgresxl_distribute_by_hash_column() ""Id"" integer NOT NULL, PRIMARY KEY (""Id"") ) -DISTRIBUTE BY HASH (Id); +DISTRIBUTE BY HASH (""Id""); "); } @@ -665,7 +665,7 @@ public void CreateTableOperation_with_postgresxl_distribute_by_modulo_column() var distribution = new PostgresXlDistributeBy(op); distribution.DistributionStrategy = PostgresXlDistributeByStrategy.None; distribution.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.Modulo; - distribution.DistributeByColumnName = "Id"; + distribution.DistributeByPropertyName = "Id"; Generate(op); @@ -674,7 +674,7 @@ public void CreateTableOperation_with_postgresxl_distribute_by_modulo_column() ""Id"" integer NOT NULL, PRIMARY KEY (""Id"") ) -DISTRIBUTE BY MODULO (Id); +DISTRIBUTE BY MODULO (""Id""); "); } @@ -705,7 +705,7 @@ public void CreateTableOperation_with_postgresxl_distributed_by_column() var distribution = new PostgresXlDistributeBy(op); distribution.DistributionStrategy = PostgresXlDistributeByStrategy.None; - distribution.DistributeByColumnName = "Id"; + distribution.DistributeByPropertyName = "Id"; Generate(op); @@ -714,7 +714,7 @@ public void CreateTableOperation_with_postgresxl_distributed_by_column() ""Id"" integer NOT NULL, PRIMARY KEY (""Id"") ) -DISTRIBUTED BY (Id); +DISTRIBUTED BY (""Id""); "); } @@ -822,7 +822,7 @@ public void CreateTableOperation_with_postgresxl_diststyle_key() var distribution = new PostgresXlDistributeBy(op); distribution.DistributionStyle = PostgresXlDistributionStyle.Key; - distribution.DistributeByColumnName = "Id"; + distribution.DistributeByPropertyName = "Id"; Generate(op); @@ -831,7 +831,7 @@ public void CreateTableOperation_with_postgresxl_diststyle_key() ""Id"" integer NOT NULL, PRIMARY KEY (""Id"") ) -DISTSTYLE KEY DISTKEY (Id); +DISTSTYLE KEY DISTKEY (""Id""); "); } [Fact] From fe5734b8ff51cbdc1a1f46bd6d56a31b8c7c4628 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Tue, 6 Apr 2021 19:46:54 +0100 Subject: [PATCH 15/19] updating PostgresXLDistributeBy Deconstruct method --- .../Internal/PostgresXlDistributeBy.cs | 19 ++++++++++--------- .../NpgsqlMigrationsSqlGenerator.cs | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs index 62dbb3954..6c4fa4a7b 100644 --- a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs @@ -61,15 +61,16 @@ public virtual string DistributeByPropertyName } } - public virtual (PostgresXlDistributeByStrategy distributionStrategy, - PostgresXlDistributeByColumnFunction distributeByColumnFunction, - PostgresXlDistributionStyle distributionStyle, - string distributeByColumnName) Deconstruct() - => ( - DistributionStrategy, - DistributeByColumnFunction, - DistributionStyle, - DistributeByPropertyName); + public void Deconstruct(out PostgresXlDistributeByStrategy distributionStrategy, + out PostgresXlDistributeByColumnFunction distributeByColumnFunction, + out PostgresXlDistributionStyle distributionStyle, + out string distributeByColumnName) + { + distributionStrategy = DistributionStrategy; + distributeByColumnFunction = DistributeByColumnFunction; + distributionStyle = DistributionStyle; + distributeByColumnName = DistributeByPropertyName; + } private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string ColumnName) GetData() { diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index c29300465..ac2d97c6c 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -198,7 +198,7 @@ protected override void Generate( if (operation[PostgresXlDistributeByAnnotationNames.DistributeBy] is string) { var distributeBy = new PostgresXlDistributeBy(operation); - var (distributionStrategy, distributeByColumnFunction, distributionStyle, distributeByColumnName) = distributeBy.Deconstruct(); + var (distributionStrategy, distributeByColumnFunction, distributionStyle, distributeByColumnName) = distributeBy; ValidateTableDistributionProperties(distributionStrategy, distributeByColumnFunction, distributionStyle, distributeByColumnName); From cd5a15a27c956ca67a09580a580053a8a09a4117 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Tue, 6 Apr 2021 20:13:23 +0100 Subject: [PATCH 16/19] moving validate method to local method --- .../NpgsqlEntityTypeBuilderExtensions.cs | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index dec5db48c..d2aec7877 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -350,7 +350,6 @@ public static EntityTypeBuilder PostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string propertyName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) - { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); Check.NotEmpty(propertyName, nameof(propertyName)); @@ -358,12 +357,25 @@ public static EntityTypeBuilder PostgresXlDistributeBy( var distribute = entityTypeBuilder.Metadata.GetPostgresXlDistributeBy(); distribute.DistributionStrategy = PostgresXlDistributeByStrategy.None; - distribute.DistributeByColumnFunction = PostgresXlDistributeByColumnFunction.None; + distribute.DistributeByColumnFunction = distributeByColumnFunction; distribute.DistributeByPropertyName = propertyName; return entityTypeBuilder; } + public static EntityTypeBuilder PostgresXlDistributeBy( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + [NotNull] Expression> propertyExpression, + PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + Check.NotNull(propertyExpression, nameof(propertyExpression)); + + entityTypeBuilder.PostgresXlDistributeBy(propertyExpression.GetPropertyAccess().Name, distributeByColumnFunction); + + return entityTypeBuilder; + } + public static EntityTypeBuilder PostgresXlDistributeBy( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string propertyName, @@ -416,6 +428,19 @@ public static EntityTypeBuilder PostgresXlDistributionStyleKey( return entityTypeBuilder; } + public static EntityTypeBuilder PostgresXlDistributionStyleKey( + [NotNull] this EntityTypeBuilder entityTypeBuilder, + [NotNull] Expression> distributionKeyExpression) + where TEntity : class + { + Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); + Check.NotNull(distributionKeyExpression, nameof(distributionKeyExpression)); + + entityTypeBuilder.PostgresXlDistributionStyleKey(distributionKeyExpression.GetPropertyAccess().Name); + + return entityTypeBuilder; + } + public static EntityTypeBuilder PostgresXlDistributionStyleKey( [NotNull] this EntityTypeBuilder entityTypeBuilder, [NotNull] string distributionKey) From 7be8749233f414a39c556cefc19ccfd574cc77b6 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Tue, 6 Apr 2021 20:14:25 +0100 Subject: [PATCH 17/19] adding strongly typed overloads for PostgresXlDistributeBy EntityTypeBuilder extension methods --- .../NpgsqlMigrationsSqlGenerator.cs | 223 +++++++++--------- 1 file changed, 113 insertions(+), 110 deletions(-) diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index ac2d97c6c..6bd080f42 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -289,6 +289,119 @@ protected override void Generate( builder.AppendLine(";"); EndStatement(builder); } + + static void ValidateTableDistributionProperties( + PostgresXlDistributeByStrategy distributionStrategy, + PostgresXlDistributeByColumnFunction distributeByColumnFunction, + PostgresXlDistributionStyle distributionStyle, + // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local + string distributeByColumnName) + { + switch (distributionStrategy) + { + case PostgresXlDistributeByStrategy.Replication: + case PostgresXlDistributeByStrategy.RoundRobin: + case PostgresXlDistributeByStrategy.Randomly: + // If column is defined, throw + if (!string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); + } + + // If any others are defined, throw + if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); + } + + if (distributionStyle != PostgresXlDistributionStyle.None) + { + throw new NotSupportedException( + $"{nameof(distributionStyle)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); + } + + break; + } + + switch (distributeByColumnFunction) + { + case PostgresXlDistributeByColumnFunction.Hash: + case PostgresXlDistributeByColumnFunction.Modulo: + // If column is not defined, throw + if (string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); + } + + // If any others are defined, throw + if (distributionStrategy != PostgresXlDistributeByStrategy.None) + { + throw new NotSupportedException( + $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); + } + + if (distributionStyle != PostgresXlDistributionStyle.None) + { + throw new NotSupportedException( + $"{nameof(distributionStyle)} cannot be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); + } + + break; + } + + switch (distributionStyle) + { + case PostgresXlDistributionStyle.Key: + // If column is not defined, throw + if (string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + // If any others are defined, throw + if (distributionStrategy != PostgresXlDistributeByStrategy.None) + { + throw new NotSupportedException( + $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + break; + case PostgresXlDistributionStyle.Even: + case PostgresXlDistributionStyle.All: + // If column is defined, throw + if (!string.IsNullOrWhiteSpace(distributeByColumnName)) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + // If any others are defined, throw + if (distributionStrategy != PostgresXlDistributeByStrategy.None) + { + throw new NotSupportedException( + $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) + { + throw new NotSupportedException( + $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); + } + + // If any others are defined, throw + break; + } + } } protected override void Generate(AlterTableOperation operation, IModel model, MigrationCommandListBuilder builder) @@ -1884,117 +1997,7 @@ public IndexColumn(string name, string @operator, string collation, SortOrder so public NullSortOrder NullSortOrder { get; } } - private static void ValidateTableDistributionProperties( - PostgresXlDistributeByStrategy distributionStrategy, - PostgresXlDistributeByColumnFunction distributeByColumnFunction, - PostgresXlDistributionStyle distributionStyle, - string distributeByColumnName) - { - switch (distributionStrategy) - { - case PostgresXlDistributeByStrategy.Replication: - case PostgresXlDistributeByStrategy.RoundRobin: - case PostgresXlDistributeByStrategy.Randomly: - // If column is defined, throw - if (!string.IsNullOrWhiteSpace(distributeByColumnName)) - { - throw new NotSupportedException( - $"{nameof(distributeByColumnName)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); - } - - // If any others are defined, throw - if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) - { - throw new NotSupportedException( - $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); - } - - if (distributionStyle != PostgresXlDistributionStyle.None) - { - throw new NotSupportedException( - $"{nameof(distributionStyle)} cannot be provided when {nameof(PostgresXlDistributeByStrategy)} is specified."); - } - - break; - } - - switch (distributeByColumnFunction) - { - case PostgresXlDistributeByColumnFunction.Hash: - case PostgresXlDistributeByColumnFunction.Modulo: - // If column is not defined, throw - if (string.IsNullOrWhiteSpace(distributeByColumnName)) - { - throw new NotSupportedException( - $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); - } - - // If any others are defined, throw - if (distributionStrategy != PostgresXlDistributeByStrategy.None) - { - throw new NotSupportedException( - $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); - } - - if (distributionStyle != PostgresXlDistributionStyle.None) - { - throw new NotSupportedException( - $"{nameof(distributionStyle)} cannot be provided when {nameof(PostgresXlDistributeByColumnFunction)} is specified."); - } - - break; - } - switch (distributionStyle) - { - case PostgresXlDistributionStyle.Key: - // If column is not defined, throw - if (string.IsNullOrWhiteSpace(distributeByColumnName)) - { - throw new NotSupportedException( - $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributionStyle)} is specified."); - } - - // If any others are defined, throw - if (distributionStrategy != PostgresXlDistributeByStrategy.None) - { - throw new NotSupportedException( - $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); - } - - if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) - { - throw new NotSupportedException( - $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); - } - - break; - case PostgresXlDistributionStyle.Even: - case PostgresXlDistributionStyle.All: - // If column is defined, throw - if (!string.IsNullOrWhiteSpace(distributeByColumnName)) - { - throw new NotSupportedException( - $"{nameof(distributeByColumnName)} must be provided when {nameof(PostgresXlDistributionStyle)} is specified."); - } - - // If any others are defined, throw - if (distributionStrategy != PostgresXlDistributeByStrategy.None) - { - throw new NotSupportedException( - $"{nameof(distributionStrategy)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); - } - - if (distributeByColumnFunction != PostgresXlDistributeByColumnFunction.None) - { - throw new NotSupportedException( - $"{nameof(distributeByColumnFunction)} cannot be provided when {nameof(PostgresXlDistributionStyle)} is specified."); - } - - // If any others are defined, throw - break; - } - } #endregion } From d76d3ddf801326754ff8efc52cd80e18cbf505cf Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Wed, 7 Apr 2021 22:28:06 +0100 Subject: [PATCH 18/19] fixing nullability issues when building --- .../NpgsqlEntityTypeBuilderExtensions.cs | 32 +++++++++---------- .../NpgsqlEntityTypeExtensions.cs | 2 +- .../Internal/PostgresXlDistributeBy.cs | 29 +++++++++-------- .../NpgsqlMigrationsSqlGenerator.cs | 7 ++-- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs index 131334924..4927937cc 100644 --- a/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs +++ b/src/EFCore.PG/Extensions/BuilderExtensions/NpgsqlEntityTypeBuilderExtensions.cs @@ -331,7 +331,7 @@ public static EntityTypeBuilder UseCockroachDbInterleaveInParent PostgresXlDistributeBy( - [NotNull] this EntityTypeBuilder entityTypeBuilder, + this EntityTypeBuilder entityTypeBuilder, PostgresXlDistributeByStrategy distributeByStrategy) where TEntity : class => (EntityTypeBuilder)PostgresXlDistributeBy((EntityTypeBuilder)entityTypeBuilder, distributeByStrategy); public static EntityTypeBuilder PostgresXlDistributeBy( - [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] string propertyName, + this EntityTypeBuilder entityTypeBuilder, + string propertyName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); @@ -371,8 +371,8 @@ public static EntityTypeBuilder PostgresXlDistributeBy( } public static EntityTypeBuilder PostgresXlDistributeBy( - [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] Expression> propertyExpression, + this EntityTypeBuilder entityTypeBuilder, + Expression> propertyExpression, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); @@ -384,15 +384,15 @@ public static EntityTypeBuilder PostgresXlDistributeBy( } public static EntityTypeBuilder PostgresXlDistributeBy( - [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] string propertyName, + this EntityTypeBuilder entityTypeBuilder, + string propertyName, PostgresXlDistributeByColumnFunction distributeByColumnFunction = PostgresXlDistributeByColumnFunction.None) where TEntity : class => (EntityTypeBuilder)PostgresXlDistributeBy( (EntityTypeBuilder)entityTypeBuilder, propertyName, distributeByColumnFunction); public static EntityTypeBuilder PostgresXlDistributionStyle( - [NotNull] this EntityTypeBuilder entityTypeBuilder, + this EntityTypeBuilder entityTypeBuilder, PostgresXlDistributionStyle distributionStyle) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); @@ -414,7 +414,7 @@ public static EntityTypeBuilder PostgresXlDistributionStyle( } public static EntityTypeBuilder PostgresXlDistributionStyle( - [NotNull] this EntityTypeBuilder entityTypeBuilder, + this EntityTypeBuilder entityTypeBuilder, PostgresXlDistributionStyle distributionStyle ) where TEntity : class @@ -422,8 +422,8 @@ PostgresXlDistributionStyle distributionStyle public static EntityTypeBuilder PostgresXlDistributionStyleKey( - [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] string distributionKey) + this EntityTypeBuilder entityTypeBuilder, + string distributionKey) { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); Check.NotEmpty(distributionKey, nameof(distributionKey)); @@ -436,8 +436,8 @@ public static EntityTypeBuilder PostgresXlDistributionStyleKey( } public static EntityTypeBuilder PostgresXlDistributionStyleKey( - [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] Expression> distributionKeyExpression) + this EntityTypeBuilder entityTypeBuilder, + Expression> distributionKeyExpression) where TEntity : class { Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); @@ -449,8 +449,8 @@ public static EntityTypeBuilder PostgresXlDistributionStyleKey } public static EntityTypeBuilder PostgresXlDistributionStyleKey( - [NotNull] this EntityTypeBuilder entityTypeBuilder, - [NotNull] string distributionKey) + this EntityTypeBuilder entityTypeBuilder, + string distributionKey) where TEntity : class => (EntityTypeBuilder)PostgresXlDistributionStyleKey((EntityTypeBuilder)entityTypeBuilder, distributionKey); diff --git a/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs b/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs index d45064c52..d6ca48ceb 100644 --- a/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs +++ b/src/EFCore.PG/Extensions/MetadataExtensions/NpgsqlEntityTypeExtensions.cs @@ -97,7 +97,7 @@ public static CockroachDbInterleaveInParent GetCockroachDbInterleaveInParent(thi #region Postgres-xl Distribute By - public static PostgresXlDistributeBy GetPostgresXlDistributeBy([NotNull] this IReadOnlyEntityType entityType) + public static PostgresXlDistributeBy GetPostgresXlDistributeBy(this IReadOnlyEntityType entityType) => new(entityType); #endregion Postgres-xl Distribute By diff --git a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs index 6c4fa4a7b..ddeb5ee51 100644 --- a/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs +++ b/src/EFCore.PG/Metadata/Internal/PostgresXlDistributeBy.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#nullable enable using System; using System.Text; using JetBrains.Annotations; @@ -18,7 +19,7 @@ public class PostgresXlDistributeBy public virtual Annotatable Annotatable => (Annotatable)_annotatable; - public PostgresXlDistributeBy([NotNull] IReadOnlyAnnotatable annotatable) + public PostgresXlDistributeBy(IReadOnlyAnnotatable annotatable) => _annotatable = annotatable; public virtual PostgresXlDistributeByStrategy DistributionStrategy @@ -51,10 +52,10 @@ public virtual PostgresXlDistributionStyle DistributionStyle } } - public virtual string DistributeByPropertyName + public virtual string? DistributeByPropertyName { get => GetData().ColumnName; - [param:NotNull] set + set { var (distributionStrategy, distributeByColumnFunction, distributionStyle, _) = GetData(); SetData(distributionStrategy, distributeByColumnFunction, distributionStyle, value); @@ -64,7 +65,7 @@ public virtual string DistributeByPropertyName public void Deconstruct(out PostgresXlDistributeByStrategy distributionStrategy, out PostgresXlDistributeByColumnFunction distributeByColumnFunction, out PostgresXlDistributionStyle distributionStyle, - out string distributeByColumnName) + out string? distributeByColumnName) { distributionStrategy = DistributionStrategy; distributeByColumnFunction = DistributeByColumnFunction; @@ -72,7 +73,7 @@ public void Deconstruct(out PostgresXlDistributeByStrategy distributionStrategy, distributeByColumnName = DistributeByPropertyName; } - private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string ColumnName) GetData() + private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, string? ColumnName) GetData() { var str = Annotatable[AnnotationName] as string; return str == null @@ -84,7 +85,7 @@ private void SetData( PostgresXlDistributeByStrategy distributionStrategy, PostgresXlDistributeByColumnFunction distributeByColumnFunction, PostgresXlDistributionStyle postgresXlDistributionStyle, - string distributeByColumnName) + string? distributeByColumnName) { Annotatable[AnnotationName] = Serialize(distributionStrategy, distributeByColumnFunction, postgresXlDistributionStyle, distributeByColumnName); } @@ -93,7 +94,7 @@ private string Serialize( PostgresXlDistributeByStrategy distributionStrategy, PostgresXlDistributeByColumnFunction distributeByColumnFunction, PostgresXlDistributionStyle postgresXlDistributionStyle, - string distributeByColumnName) + string? distributeByColumnName) { var stringBuilder = new StringBuilder(); @@ -111,31 +112,31 @@ private string Serialize( private (PostgresXlDistributeByStrategy DistributionStrategy, PostgresXlDistributeByColumnFunction DistributeByColumnFunction, PostgresXlDistributionStyle DistributionStyle, - string ColumnName) + string? ColumnName) Deserialize(string str) { var position = 0; - var distributionStrategy = Enum.Parse(ExtractValue(str, ref position)); - var distributeByColumnFunction = Enum.Parse(ExtractValue(str, ref position)); - var distributionStyle = Enum.Parse(ExtractValue(str, ref position)); + var distributionStrategy = Enum.Parse(ExtractValue(str, ref position)!); + var distributeByColumnFunction = Enum.Parse(ExtractValue(str, ref position)!); + var distributionStyle = Enum.Parse(ExtractValue(str, ref position)!); var columnName = ExtractValue(str, ref position); return (distributionStrategy, distributeByColumnFunction, distributionStyle, columnName); } - private static void EscapeAndQuote(StringBuilder builder, object value) + private static void EscapeAndQuote(StringBuilder builder, object? value) { builder.Append("'"); if (value != null) { - builder.Append(value.ToString().Replace("'", "''")); + builder.Append(value.ToString()?.Replace("'", "''")); } builder.Append("'"); } - private static string ExtractValue(string value, ref int position) + private static string? ExtractValue(string value, ref int position) { position = value.IndexOf('\'', position) + 1; diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index 45cf4e34b..529013139 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using System.Globalization; @@ -215,7 +216,7 @@ protected override void Generate( .Append("DISTRIBUTE BY ") .Append(distributeByColumnFunction.ToString().ToUpperInvariant()) .Append(" (") - .Append(DelimitIdentifier(distributeByColumnName)) + .Append(DelimitIdentifier(distributeByColumnName!)) .Append(")"); } @@ -245,7 +246,7 @@ protected override void Generate( .Append("DISTSTYLE ") .Append(distributionStyle.ToString().ToUpperInvariant()) .Append(" DISTKEY (") - .Append(DelimitIdentifier(distributeByColumnName)) + .Append(DelimitIdentifier(distributeByColumnName!)) .Append(")"); } else if (distributionStyle == PostgresXlDistributionStyle.All || distributionStyle == PostgresXlDistributionStyle.Even) @@ -294,7 +295,7 @@ static void ValidateTableDistributionProperties( PostgresXlDistributeByColumnFunction distributeByColumnFunction, PostgresXlDistributionStyle distributionStyle, // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local - string distributeByColumnName) + string? distributeByColumnName) { switch (distributionStrategy) { From 016212fec322a77b5e873fdf831b1792ea79bda9 Mon Sep 17 00:00:00 2001 From: Jon Morgan Date: Wed, 7 Apr 2021 22:29:59 +0100 Subject: [PATCH 19/19] fixing whitespace --- src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs index 529013139..0a6d74aad 100644 --- a/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs +++ b/src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs @@ -1996,8 +1996,6 @@ public IndexColumn(string name, string? @operator, string? collation, SortOrder public NullSortOrder NullSortOrder { get; } } - - #endregion } }