Skip to content

Commit b09d7b4

Browse files
Merge pull request #91 from dotnetprojects/get-columns-postgre
Postgre read type and default values
2 parents ccee803 + e24fe5d commit b09d7b4

File tree

7 files changed

+439
-33
lines changed

7 files changed

+439
-33
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Data;
3+
using System.Linq;
4+
using DotNetProjects.Migrator.Framework;
5+
using NUnit.Framework;
6+
7+
namespace Migrator.Tests.Providers.PostgreSQL;
8+
9+
[TestFixture]
10+
[Category("Postgre")]
11+
public class PostgreSQLTransformationProvider_GetColumnsDefaultTypeTests : PostgreSQLTransformationProviderTestBase
12+
{
13+
private const decimal DecimalDefaultValue = 14.56565m;
14+
15+
[Test]
16+
public void GetColumns_DataTypeResolveSucceeds()
17+
{
18+
// Arrange
19+
var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc);
20+
var guidDefaultValue = Guid.NewGuid();
21+
22+
const string testTableName = "MyDefaultTestTable";
23+
24+
const string dateTimeColumnName1 = "datetimecolumn1";
25+
const string dateTimeColumnName2 = "datetimecolumn2";
26+
const string decimalColumnName1 = "decimalcolumn";
27+
const string guidColumnName1 = "guidcolumn1";
28+
const string booleanColumnName1 = "booleancolumn1";
29+
const string int32ColumnName1 = "int32column1";
30+
const string int64ColumnName1 = "int64column1";
31+
const string stringColumnName1 = "stringcolumn1";
32+
const string binaryColumnName1 = "binarycolumn1";
33+
34+
// Should be extended by remaining types
35+
Provider.AddTable(testTableName,
36+
new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue),
37+
new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue),
38+
new Column(decimalColumnName1, DbType.Decimal, DecimalDefaultValue),
39+
new Column(guidColumnName1, DbType.Guid, guidDefaultValue),
40+
41+
// other boolean default values are tested in another test
42+
new Column(booleanColumnName1, DbType.Boolean, true),
43+
44+
new Column(int32ColumnName1, DbType.Int32, defaultValue: 43),
45+
new Column(int64ColumnName1, DbType.Int64, defaultValue: 88),
46+
new Column(stringColumnName1, DbType.String, defaultValue: "Hello"),
47+
new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 })
48+
);
49+
50+
// Act
51+
var columns = Provider.GetColumns(testTableName);
52+
53+
// Assert
54+
var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1);
55+
var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2);
56+
var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1);
57+
var guidColumn1 = columns.Single(x => x.Name == guidColumnName1);
58+
var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1);
59+
var int32Column1 = columns.Single(x => x.Name == int32ColumnName1);
60+
var int64Column1 = columns.Single(x => x.Name == int64ColumnName1);
61+
var stringColumn1 = columns.Single(x => x.Name == stringColumnName1);
62+
var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1);
63+
64+
Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue));
65+
Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue));
66+
Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(DecimalDefaultValue));
67+
Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue));
68+
Assert.That(booleanColumn1.DefaultValue, Is.True);
69+
Assert.That(int32Column1.DefaultValue, Is.EqualTo(43));
70+
Assert.That(int64Column1.DefaultValue, Is.EqualTo(88));
71+
Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello"));
72+
Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 }));
73+
}
74+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System.Data;
2+
using System.Linq;
3+
using DotNetProjects.Migrator.Framework;
4+
using NUnit.Framework;
5+
6+
namespace Migrator.Tests.Providers.PostgreSQL;
7+
8+
[TestFixture]
9+
[Category("Postgre")]
10+
public class PostgreSQLTransformationProvider_GetColumnTypeTests : PostgreSQLTransformationProviderTestBase
11+
{
12+
[Test]
13+
public void GetColumns_DataTypeResolveSucceeds()
14+
{
15+
// Arrange
16+
const string testTableName = "MyDefaultTestTable";
17+
const string dateTimeColumnName1 = "datetimecolumn1";
18+
const string dateTimeColumnName2 = "datetimecolumn2";
19+
const string decimalColumnName1 = "decimalcolumn";
20+
const string guidColumnName1 = "guidcolumn1";
21+
const string booleanColumnName1 = "booleancolumn1";
22+
const string int32ColumnName1 = "int32column1";
23+
const string int64ColumnName1 = "int64column1";
24+
const string stringColumnName1 = "stringcolumn1";
25+
const string stringColumnName2 = "stringcolumn2";
26+
const string binaryColumnName1 = "binarycolumn";
27+
28+
// Should be extended by remaining types
29+
Provider.AddTable(testTableName,
30+
new Column(dateTimeColumnName1, DbType.DateTime),
31+
new Column(dateTimeColumnName2, DbType.DateTime2),
32+
new Column(decimalColumnName1, DbType.Decimal),
33+
new Column(guidColumnName1, DbType.Guid),
34+
new Column(booleanColumnName1, DbType.Boolean),
35+
new Column(int32ColumnName1, DbType.Int32),
36+
new Column(int64ColumnName1, DbType.Int64),
37+
new Column(stringColumnName1, DbType.String),
38+
new Column(stringColumnName2, DbType.String) { Size = 30 },
39+
new Column(binaryColumnName1, DbType.Binary)
40+
);
41+
42+
// Act
43+
var columns = Provider.GetColumns(testTableName);
44+
45+
var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1);
46+
var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2);
47+
var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1);
48+
var guidColumn1 = columns.Single(x => x.Name == guidColumnName1);
49+
var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1);
50+
var int32Column1 = columns.Single(x => x.Name == int32ColumnName1);
51+
var int64column1 = columns.Single(x => x.Name == int64ColumnName1);
52+
var stringColumn1 = columns.Single(x => x.Name == stringColumnName1);
53+
var stringColumn2 = columns.Single(x => x.Name == stringColumnName2);
54+
var binaryColumn1 = columns.Single(x => x.Name == binaryColumnName1);
55+
56+
57+
// Assert
58+
Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime));
59+
Assert.That(dateTimeColumn1.Precision, Is.EqualTo(3));
60+
Assert.That(dateTimeColumn2.Type, Is.EqualTo(DbType.DateTime2));
61+
Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6));
62+
Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal));
63+
Assert.That(decimalColumn1.Precision, Is.EqualTo(19));
64+
Assert.That(decimalColumn1.Scale, Is.EqualTo(5));
65+
Assert.That(guidColumn1.Type, Is.EqualTo(DbType.Guid));
66+
Assert.That(booleanColumn1.Type, Is.EqualTo(DbType.Boolean));
67+
Assert.That(int32Column1.Type, Is.EqualTo(DbType.Int32));
68+
Assert.That(int64column1.Type, Is.EqualTo(DbType.Int64));
69+
Assert.That(stringColumn1.Type, Is.EqualTo(DbType.String));
70+
Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String));
71+
Assert.That(stringColumn2.Size, Is.EqualTo(30));
72+
Assert.That(binaryColumn1.Type, Is.EqualTo(DbType.Binary));
73+
}
74+
}

src/Migrator/Framework/Column.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#endregion
1313

14+
using System;
1415
using System.Data;
1516

1617
namespace DotNetProjects.Migrator.Framework;
@@ -20,6 +21,8 @@ namespace DotNetProjects.Migrator.Framework;
2021
/// </summary>
2122
public class Column : IColumn, IDbField
2223
{
24+
private object _defaultValue;
25+
2326
public Column(string name)
2427
{
2528
Name = name;
@@ -147,13 +150,34 @@ public DbType Type
147150

148151
public int Size { get; set; }
149152

153+
/// <summary>
154+
/// Gets or sets the precision for NUMERIC/DECIMAL
155+
/// </summary>
150156
public int? Precision { get; set; }
151157

158+
/// <summary>
159+
/// Gets or sets the scale for NUMERIC/DECIMAL
160+
/// </summary>
152161
public int? Scale { get; set; }
153162

154163
public ColumnProperty ColumnProperty { get; set; }
155164

156-
public object DefaultValue { get; set; }
165+
public object DefaultValue
166+
{
167+
get => _defaultValue;
168+
set
169+
{
170+
if (value is DateTime defaultValueDateTime)
171+
{
172+
if (defaultValueDateTime.Kind != DateTimeKind.Utc)
173+
{
174+
throw new Exception("We only accept UTC values as default DateTime values.");
175+
}
176+
}
177+
178+
_defaultValue = value;
179+
}
180+
}
157181

158182
public bool IsIdentity
159183
{

src/Migrator/Providers/Dialect.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Data;
4+
using System.Globalization;
45
using DotNetProjects.Migrator.Framework;
56

67
namespace DotNetProjects.Migrator.Providers;
@@ -344,7 +345,9 @@ public virtual string Default(object defaultValue)
344345
}
345346
else if (defaultValue is Guid)
346347
{
347-
return string.Format("DEFAULT '{0}'", defaultValue.ToString());
348+
var guidValue = string.Format("DEFAULT '{0}'", defaultValue.ToString());
349+
350+
return guidValue;
348351
}
349352
else if (defaultValue is DateTime)
350353
{
@@ -355,6 +358,16 @@ public virtual string Default(object defaultValue)
355358
defaultValue = ((string)defaultValue).Replace("'", "''");
356359
defaultValue = "'" + defaultValue + "'";
357360
}
361+
else if (defaultValue is decimal)
362+
{
363+
// .ToString("N") does not exist in old .NET version
364+
defaultValue = Convert.ToString(defaultValue, CultureInfo.InvariantCulture);
365+
}
366+
else if (defaultValue is byte[] byteArray)
367+
{
368+
var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower();
369+
defaultValue = $"'\\x{convertedString}'";
370+
}
358371

359372
return string.Format("DEFAULT {0}", defaultValue);
360373
}

src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ public PostgreSQLDialect()
1818
RegisterColumnType(DbType.Byte, "int2");
1919
RegisterColumnType(DbType.Currency, "decimal(16,4)");
2020
RegisterColumnType(DbType.Date, "date");
21-
RegisterColumnType(DbType.DateTime, "timestamptz");
22-
RegisterColumnType(DbType.DateTime2, "timestamptz");
21+
22+
// 8 bytes - resolution 1 microsecond
23+
RegisterColumnType(DbType.DateTime, "timestamp(3)");
24+
25+
// 8 bytes - resolution 1 microsecond
26+
// We do not use timezone any more - this is near a datetime2 in SQL Server
27+
RegisterColumnType(DbType.DateTime2, "timestamp(6)");
2328
RegisterColumnType(DbType.DateTimeOffset, "timestamptz");
2429
RegisterColumnType(DbType.Decimal, "decimal(19,5)");
2530
RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)");

0 commit comments

Comments
 (0)