diff --git a/src/FluentMigrator.Extensions.Postgres/Postgres/PostgresExtensions.OverridingIdentityValues.cs b/src/FluentMigrator.Extensions.Postgres/Postgres/PostgresExtensions.OverridingIdentityValues.cs
new file mode 100644
index 000000000..03b2985a5
--- /dev/null
+++ b/src/FluentMigrator.Extensions.Postgres/Postgres/PostgresExtensions.OverridingIdentityValues.cs
@@ -0,0 +1,73 @@
+#region License
+// Copyright (c) 2021, FluentMigrator Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+using System;
+
+using FluentMigrator.Builders.Insert;
+using FluentMigrator.Infrastructure;
+using FluentMigrator.Infrastructure.Extensions;
+
+namespace FluentMigrator.Postgres
+{
+ public static partial class PostgresExtensions
+ {
+ public const string OverridingIdentityValues = "PostgresOverridingIdentityValues";
+
+ ///
+ /// Adds an OVERRIDING SYSTEM VALUE clause in the current expression.
+ /// This enables the system-generated values to be overriden with the user-specified explicit values (other than DEFAULT)
+ /// for identity columns defined as GENERATED ALWAYS
+ ///
+ /// The current expression
+ /// The current expression
+ public static IInsertDataSyntax WithOverridingSystemValue(this IInsertDataSyntax expression) =>
+ SetOverridingIdentityValues(expression, PostgresOverridingIdentityValuesType.System, nameof(WithOverridingSystemValue));
+
+ ///
+ /// Adds an OVERRIDING USER VALUE clause in the current expression.
+ /// Any user-specified values will be ignored and the system-generated values will be applied
+ /// for identity columns defined as GENERATED BY DEFAULT
+ ///
+ /// The current expression
+ /// The current expression
+ public static IInsertDataSyntax WithOverridingUserValue(this IInsertDataSyntax expression) =>
+ SetOverridingIdentityValues(expression, PostgresOverridingIdentityValuesType.User, nameof(WithOverridingUserValue));
+
+ ///
+ /// Set the additional feature for overriding identity values with the specified
+ /// on the provided expression
+ ///
+ ///
+ private static IInsertDataSyntax SetOverridingIdentityValues(
+ IInsertDataSyntax expression,
+ PostgresOverridingIdentityValuesType overridingType,
+ string callingMethod)
+ {
+ if (!(expression is ISupportAdditionalFeatures castExpression))
+ {
+ throw new InvalidOperationException(
+ string.Format(
+ ErrorMessages.MethodXMustBeCalledOnObjectImplementingY,
+ callingMethod,
+ nameof(ISupportAdditionalFeatures)));
+ }
+
+ castExpression.SetAdditionalFeature(OverridingIdentityValues, overridingType);
+
+ return expression;
+ }
+ }
+}
diff --git a/src/FluentMigrator.Extensions.Postgres/PostgresOverridingIdentityValuesType.cs b/src/FluentMigrator.Extensions.Postgres/PostgresOverridingIdentityValuesType.cs
new file mode 100644
index 000000000..67cae7d0c
--- /dev/null
+++ b/src/FluentMigrator.Extensions.Postgres/PostgresOverridingIdentityValuesType.cs
@@ -0,0 +1,33 @@
+#region License
+// Copyright (c) 2021, FluentMigrator Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+namespace FluentMigrator
+{
+ ///
+ /// Determines if the system-generated values or the user-supplied values are applied for identity columns
+ ///
+ public enum PostgresOverridingIdentityValuesType
+ {
+ ///
+ /// Overrides the system-generated values with user-supplied values for identity columns
+ ///
+ System,
+ ///
+ /// Ignores the user-supplied values and applies the system-generated values for identity columns
+ ///
+ User,
+ }
+}
diff --git a/src/FluentMigrator.Runner.Postgres/Generators/Postgres/Postgres10_0Generator.cs b/src/FluentMigrator.Runner.Postgres/Generators/Postgres/Postgres10_0Generator.cs
index f85e434f7..908f582ac 100644
--- a/src/FluentMigrator.Runner.Postgres/Generators/Postgres/Postgres10_0Generator.cs
+++ b/src/FluentMigrator.Runner.Postgres/Generators/Postgres/Postgres10_0Generator.cs
@@ -16,6 +16,8 @@
using System.Collections.Generic;
+using FluentMigrator.Expressions;
+using FluentMigrator.Infrastructure.Extensions;
using FluentMigrator.Postgres;
using JetBrains.Annotations;
@@ -61,5 +63,21 @@ protected override HashSet GetAllowIndexStorageParameters()
return allow;
}
+
+ ///
+ protected override string GetOverridingIdentityValuesString(InsertDataExpression expression)
+ {
+ if (!expression.AdditionalFeatures.ContainsKey(PostgresExtensions.OverridingIdentityValues))
+ {
+ return string.Empty;
+ }
+
+ var overridingIdentityValues =
+ expression.GetAdditionalFeature(
+ PostgresExtensions.OverridingIdentityValues);
+
+ return string.Format(" OVERRIDING {0} VALUE",
+ overridingIdentityValues == PostgresOverridingIdentityValuesType.User ? "USER" : "SYSTEM");
+ }
}
}
diff --git a/src/FluentMigrator.Runner.Postgres/Generators/Postgres/PostgresGenerator.cs b/src/FluentMigrator.Runner.Postgres/Generators/Postgres/PostgresGenerator.cs
index 54b217f4f..a021f7049 100644
--- a/src/FluentMigrator.Runner.Postgres/Generators/Postgres/PostgresGenerator.cs
+++ b/src/FluentMigrator.Runner.Postgres/Generators/Postgres/PostgresGenerator.cs
@@ -444,7 +444,11 @@ public override string Generate(InsertDataExpression expression)
var columns = GetColumnList(columnNames);
var data = GetDataList(columnData);
- result.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2});", Quoter.QuoteTableName(expression.TableName, expression.SchemaName), columns, data);
+ result.AppendFormat("INSERT INTO {0} ({1}){3} VALUES ({2});",
+ Quoter.QuoteTableName(expression.TableName, expression.SchemaName),
+ columns,
+ data,
+ GetOverridingIdentityValuesString(expression));
}
return result.ToString();
}
@@ -629,5 +633,15 @@ public override string Generate(DeleteSequenceExpression expression)
{
return string.Format("{0};", base.Generate(expression));
}
+
+ protected virtual string GetOverridingIdentityValuesString(InsertDataExpression expression)
+ {
+ if (!expression.AdditionalFeatures.ContainsKey(PostgresExtensions.OverridingIdentityValues))
+ {
+ return string.Empty;
+ }
+
+ throw new NotSupportedException("The current version doesn't support OVERRIDING {SYSTEM|USER} VALUE. Please use Postgres 10+.");
+ }
}
}
diff --git a/test/FluentMigrator.Tests/Unit/Builders/Insert/InsertDataExpressionBuilderTests.cs b/test/FluentMigrator.Tests/Unit/Builders/Insert/InsertDataExpressionBuilderTests.cs
index 5e2d74464..11d2c4ffc 100644
--- a/test/FluentMigrator.Tests/Unit/Builders/Insert/InsertDataExpressionBuilderTests.cs
+++ b/test/FluentMigrator.Tests/Unit/Builders/Insert/InsertDataExpressionBuilderTests.cs
@@ -20,6 +20,7 @@
using FluentMigrator.Builders.Insert;
using FluentMigrator.Expressions;
+using FluentMigrator.Postgres;
using FluentMigrator.SqlServer;
using NUnit.Framework;
@@ -96,5 +97,81 @@ public void SqlServerIdentityInsertCalledTwiceAddsCorrectAdditionalFeature()
expression.AdditionalFeatures.ShouldContain(
new KeyValuePair(SqlServerExtensions.IdentityInsert, true));
}
+
+ [Test]
+ public void PostgresOverridingSystemValueAddsCorrectAdditionalFeature()
+ {
+ var expression = new InsertDataExpression();
+ var builder = new InsertDataExpressionBuilder(expression);
+ builder.WithOverridingSystemValue();
+
+ expression.AdditionalFeatures.ShouldContain(
+ new KeyValuePair(
+ PostgresExtensions.OverridingIdentityValues,
+ PostgresOverridingIdentityValuesType.System));
+ }
+
+ [Test]
+ public void PostgresOverridingSystemValueCalledTwiceAddsCorrectAdditionalFeature()
+ {
+ var expression = new InsertDataExpression();
+ var builder = new InsertDataExpressionBuilder(expression);
+ builder.WithOverridingSystemValue().WithOverridingSystemValue();
+
+ expression.AdditionalFeatures.ShouldContain(
+ new KeyValuePair(
+ PostgresExtensions.OverridingIdentityValues,
+ PostgresOverridingIdentityValuesType.System));
+ }
+
+ [Test]
+ public void PostgresOverridingUserValueAddsCorrectAdditionalFeature()
+ {
+ var expression = new InsertDataExpression();
+ var builder = new InsertDataExpressionBuilder(expression);
+ builder.WithOverridingUserValue();
+
+ expression.AdditionalFeatures.ShouldContain(
+ new KeyValuePair(
+ PostgresExtensions.OverridingIdentityValues,
+ PostgresOverridingIdentityValuesType.User));
+ }
+
+ [Test]
+ public void PostgresOverridingUserValueCalledTwiceAddsCorrectAdditionalFeature()
+ {
+ var expression = new InsertDataExpression();
+ var builder = new InsertDataExpressionBuilder(expression);
+ builder.WithOverridingUserValue().WithOverridingUserValue();
+
+ expression.AdditionalFeatures.ShouldContain(
+ new KeyValuePair(
+ PostgresExtensions.OverridingIdentityValues,
+ PostgresOverridingIdentityValuesType.User));
+ }
+
+ [Test]
+ public void PostgresOverridingIdentityValuesCalledWithDifferentTypeAddsCorrectAdditionalFeature()
+ {
+ // If both WithOverridingSystemValue() and WithOverridingUserValue() are called on the same expression,
+ // then the latest value should be set in the additional features
+
+ var expressionForUserValue = new InsertDataExpression();
+ var builderForUserValue = new InsertDataExpressionBuilder(expressionForUserValue);
+ builderForUserValue.WithOverridingSystemValue().WithOverridingUserValue();
+
+ var expressionForSystemValue = new InsertDataExpression();
+ var builderForSystemValue = new InsertDataExpressionBuilder(expressionForSystemValue);
+ builderForSystemValue.WithOverridingUserValue().WithOverridingSystemValue();
+
+ expressionForUserValue.AdditionalFeatures.ShouldContain(
+ new KeyValuePair(
+ PostgresExtensions.OverridingIdentityValues,
+ PostgresOverridingIdentityValuesType.User));
+ expressionForSystemValue.AdditionalFeatures.ShouldContain(
+ new KeyValuePair(
+ PostgresExtensions.OverridingIdentityValues,
+ PostgresOverridingIdentityValuesType.System));
+ }
}
}
diff --git a/test/FluentMigrator.Tests/Unit/Generators/Postgres/PostgresDataTests.cs b/test/FluentMigrator.Tests/Unit/Generators/Postgres/PostgresDataTests.cs
index 027c0e8ba..cec7b34ba 100644
--- a/test/FluentMigrator.Tests/Unit/Generators/Postgres/PostgresDataTests.cs
+++ b/test/FluentMigrator.Tests/Unit/Generators/Postgres/PostgresDataTests.cs
@@ -1,3 +1,6 @@
+using System;
+
+using FluentMigrator.Postgres;
using FluentMigrator.Runner.Generators.Postgres;
using FluentMigrator.Runner.Processors.Postgres;
@@ -16,7 +19,7 @@ public class PostgresDataTests : BaseDataTests
public void Setup()
{
var quoter = new PostgresQuoter(new PostgresOptions());
- Generator = new PostgresGenerator(quoter);
+ Generator = CreateGenerator(quoter);
}
[Test]
@@ -128,6 +131,24 @@ public override void CanInsertGuidDataWithDefaultSchema()
result.ShouldBe(string.Format("INSERT INTO \"public\".\"TestTable1\" (\"guid\") VALUES ('{0}');", GeneratorTestHelper.TestGuid));
}
+ [Test]
+ public virtual void CanInsertWithOverridingSystemValue()
+ {
+ var expression = GeneratorTestHelper.GetInsertDataExpression();
+ expression.AdditionalFeatures[PostgresExtensions.OverridingIdentityValues] = PostgresOverridingIdentityValuesType.System;
+
+ Should.Throw(() => Generator.Generate(expression));
+ }
+
+ [Test]
+ public virtual void CanInsertWithOverridingUserValue()
+ {
+ var expression = GeneratorTestHelper.GetInsertDataExpression();
+ expression.AdditionalFeatures[PostgresExtensions.OverridingIdentityValues] = PostgresOverridingIdentityValuesType.User;
+
+ Should.Throw(() => Generator.Generate(expression));
+ }
+
[Test]
public override void CanUpdateDataForAllDataWithCustomSchema()
{
@@ -174,5 +195,10 @@ public override void CanUpdateDataWithDbNullCriteria()
var result = Generator.Generate(expression);
result.ShouldBe("UPDATE \"public\".\"TestTable1\" SET \"Name\" = 'Just''in', \"Age\" = 25 WHERE \"Id\" = 9 AND \"Homepage\" IS NULL;");
}
+
+ protected virtual PostgresGenerator CreateGenerator(PostgresQuoter quoter)
+ {
+ return new PostgresGenerator(quoter);
+ }
}
}
diff --git a/test/FluentMigrator.Tests/Unit/Generators/Postgres10_0/Postgres10_0DataTests.cs b/test/FluentMigrator.Tests/Unit/Generators/Postgres10_0/Postgres10_0DataTests.cs
new file mode 100644
index 000000000..26a1dbc5c
--- /dev/null
+++ b/test/FluentMigrator.Tests/Unit/Generators/Postgres10_0/Postgres10_0DataTests.cs
@@ -0,0 +1,62 @@
+#region License
+// Copyright (c) 2021, FluentMigrator Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+using FluentMigrator.Postgres;
+using FluentMigrator.Runner.Generators.Postgres;
+using FluentMigrator.Tests.Unit.Generators.Postgres;
+
+using NUnit.Framework;
+
+using Shouldly;
+
+namespace FluentMigrator.Tests.Unit.Generators.Postgres10_0
+{
+ [TestFixture]
+ public class Postgres10_0DataTests : PostgresDataTests
+ {
+ ///
+ protected override PostgresGenerator CreateGenerator(PostgresQuoter quoter)
+ {
+ return new Postgres10_0Generator(quoter);
+ }
+
+ [Test]
+ public override void CanInsertWithOverridingSystemValue()
+ {
+ var expression = GeneratorTestHelper.GetInsertDataExpression();
+ expression.AdditionalFeatures[PostgresExtensions.OverridingIdentityValues] = PostgresOverridingIdentityValuesType.System;
+
+ var expected = "INSERT INTO \"public\".\"TestTable1\" (\"Id\",\"Name\",\"Website\") OVERRIDING SYSTEM VALUE VALUES (1,'Just''in','codethinked.com');";
+ expected += "INSERT INTO \"public\".\"TestTable1\" (\"Id\",\"Name\",\"Website\") OVERRIDING SYSTEM VALUE VALUES (2,'Na\\te','kohari.org');";
+
+ var result = Generator.Generate(expression);
+ result.ShouldBe(expected);
+ }
+
+ [Test]
+ public override void CanInsertWithOverridingUserValue()
+ {
+ var expression = GeneratorTestHelper.GetInsertDataExpression();
+ expression.AdditionalFeatures[PostgresExtensions.OverridingIdentityValues] = PostgresOverridingIdentityValuesType.User;
+
+ var expected = "INSERT INTO \"public\".\"TestTable1\" (\"Id\",\"Name\",\"Website\") OVERRIDING USER VALUE VALUES (1,'Just''in','codethinked.com');";
+ expected += "INSERT INTO \"public\".\"TestTable1\" (\"Id\",\"Name\",\"Website\") OVERRIDING USER VALUE VALUES (2,'Na\\te','kohari.org');";
+
+ var result = Generator.Generate(expression);
+ result.ShouldBe(expected);
+ }
+ }
+}
diff --git a/test/FluentMigrator.Tests/Unit/Generators/Postgres11_0/Postgres11_0DataTests.cs b/test/FluentMigrator.Tests/Unit/Generators/Postgres11_0/Postgres11_0DataTests.cs
new file mode 100644
index 000000000..109e25249
--- /dev/null
+++ b/test/FluentMigrator.Tests/Unit/Generators/Postgres11_0/Postgres11_0DataTests.cs
@@ -0,0 +1,30 @@
+#region License
+// Copyright (c) 2021, FluentMigrator Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#endregion
+
+using FluentMigrator.Runner.Generators.Postgres;
+using FluentMigrator.Tests.Unit.Generators.Postgres10_0;
+
+namespace FluentMigrator.Tests.Unit.Generators.Postgres11_0
+{
+ public class Postgres11_0DataTests : Postgres10_0DataTests
+ {
+ ///
+ protected override PostgresGenerator CreateGenerator(PostgresQuoter quoter)
+ {
+ return new Postgres11_0Generator(quoter);
+ }
+ }
+}