提交 a5687b08 编写于 作者: S Shay Rojansky

Fixes to array facet type mapping handling

Fixes #1149
上级 5a87cc80
......@@ -400,16 +400,25 @@ protected virtual RelationalTypeMapping FindArrayMapping(in RelationalTypeMappin
{
// PostgreSQL array type names are the element plus []
var storeType = mappingInfo.StoreTypeName;
var storeTypeNameBase = mappingInfo.StoreTypeNameBase;
if (storeType != null)
{
if (!storeType.EndsWith("[]"))
return null;
// Construct a RelationalTypeMappingInfo for the element type and look that up
// Note that we scaffold PostgreSQL arrays to C# arrays, not lists (which are also supported)
// TODO: In theory support the multiple mappings just like we do with scalars above
// (e.g. DateTimeOffset[] vs. DateTime[]
var elementMapping = FindMapping(storeType.Substring(0, storeType.Length - 2));
var elementMapping = FindMapping(new RelationalTypeMappingInfo(
storeType.Substring(0, storeType.Length - 2),
storeTypeNameBase.Substring(0, storeTypeNameBase.Length - 2),
mappingInfo.IsUnicode,
mappingInfo.Size,
mappingInfo.Precision,
mappingInfo.Scale));
if (elementMapping != null)
return StoreTypeMappings.GetOrAdd(storeType,
new RelationalTypeMapping[] { new NpgsqlArrayTypeMapping(storeType, elementMapping) })[0];
......@@ -514,5 +523,60 @@ protected virtual RelationalTypeMapping FindUserRangeMapping(in RelationalTypeMa
return rangeMapping;
}
// We override to support parsing array store names (e.g. varchar(32)[]), timestamp(5) with time zone, etc.
protected override string ParseStoreTypeName(
string storeTypeName,
out bool? unicode,
out int? size,
out int? precision,
out int? scale)
{
unicode = null;
size = null;
precision = null;
scale = null;
if (storeTypeName != null)
{
var openParen = storeTypeName.IndexOf("(", StringComparison.Ordinal);
if (openParen > 0)
{
var closeParen = storeTypeName.IndexOf(")", openParen + 1, StringComparison.Ordinal);
if (closeParen > openParen)
{
var comma = storeTypeName.IndexOf(",", openParen + 1, StringComparison.Ordinal);
if (comma > openParen
&& comma < closeParen)
{
if (int.TryParse(storeTypeName.Substring(openParen + 1, comma - openParen - 1), out var parsedPrecision))
{
precision = parsedPrecision;
}
if (int.TryParse(storeTypeName.Substring(comma + 1, closeParen - comma - 1), out var parsedScale))
{
scale = parsedScale;
}
}
else if (int.TryParse(
storeTypeName.Substring(openParen + 1, closeParen - openParen - 1).Trim(), out var parsedSize))
{
size = parsedSize;
precision = parsedSize;
}
// There may be stuff after the closing parentheses (e.g. varchar(32)[])
var preParens = storeTypeName.Substring(0, openParen).Trim();
var postParens = storeTypeName.Substring(closeParen + 1).TrimEnd();
return postParens.Length > 0
? preParens + postParens
: preParens;
}
}
}
return storeTypeName;
}
}
}
......@@ -707,7 +707,9 @@ public void Specific_max_length_are_add_to_store_type()
""char10Column"" char(10) NULL,
""varchar66Column"" varchar(66) NULL,
""bit111Column"" bit(111) NULL,
""varbit123Column"" varbit(123) NULL
""varbit123Column"" varbit(123) NULL,
""varchar66ArrayColumn"" varchar(66)[] NULL,
""varbit123ArrayColumn"" varbit(123)[] NULL
)",
Enumerable.Empty<string>(),
Enumerable.Empty<string>(),
......@@ -719,6 +721,8 @@ public void Specific_max_length_are_add_to_store_type()
Assert.Equal("character varying(66)", columns.Single(c => c.Name == "varchar66Column").StoreType);
Assert.Equal("bit(111)", columns.Single(c => c.Name == "bit111Column").StoreType);
Assert.Equal("bit varying(123)", columns.Single(c => c.Name == "varbit123Column").StoreType);
Assert.Equal("character varying(66)[]", columns.Single(c => c.Name == "varchar66ArrayColumn").StoreType);
Assert.Equal("bit varying(123)[]", columns.Single(c => c.Name == "varbit123ArrayColumn").StoreType);
},
@"DROP TABLE ""LengthColumns""");
......
......@@ -6,6 +6,7 @@
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
using Npgsql.EntityFrameworkCore.PostgreSQL.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
using NpgsqlTypes;
using Xunit;
......@@ -16,6 +17,7 @@ public class NpgsqlTypeMappingSourceTest
[Theory]
[InlineData("integer", typeof(int))]
[InlineData("integer[]", typeof(int[]))]
[InlineData("timestamp with time zone", typeof(DateTime))]
[InlineData("dummy", typeof(DummyType))]
[InlineData("int4range", typeof(NpgsqlRange<int>))]
[InlineData("floatrange", typeof(NpgsqlRange<float>))]
......@@ -24,7 +26,55 @@ public class NpgsqlTypeMappingSourceTest
[InlineData("geometry(Polygon)", typeof(Polygon))]
[InlineData("geography(Point, 4326)", typeof(Point))]
public void By_StoreType(string storeType, Type expectedClrType)
=> Assert.Same(expectedClrType, Source.FindMapping(storeType).ClrType);
{
var mapping = Source.FindMapping(storeType);
Assert.Same(expectedClrType, mapping.ClrType);
Assert.Null(mapping.Size);
}
[Fact]
public void Varchar32()
{
var mapping = Source.FindMapping("varchar(32)");
Assert.Same(typeof(string), mapping.ClrType);
Assert.Equal("varchar(32)", mapping.StoreType);
Assert.Equal(32, mapping.Size);
}
[Fact]
public void Varchar32_Array()
{
var arrayMapping = Assert.IsType<NpgsqlArrayTypeMapping>(Source.FindMapping("varchar(32)[]"));
Assert.Same(typeof(string[]), arrayMapping.ClrType);
Assert.Equal("varchar(32)[]", arrayMapping.StoreType);
Assert.Null(arrayMapping.Size);
var elementMapping = arrayMapping.ElementMapping;
Assert.Same(typeof(string), elementMapping.ClrType);
Assert.Equal("varchar(32)", elementMapping.StoreType);
Assert.Equal(32, elementMapping.Size);
}
[Fact]
public void Timestamp_without_time_zone_5()
{
var mapping = Source.FindMapping("timestamp(5) without time zone");
Assert.Same(typeof(DateTime), mapping.ClrType);
Assert.Equal("timestamp(5) without time zone", mapping.StoreType);
// Precision/Scale not actually exposed on RelationalTypeMapping...
}
[Fact]
public void Timestamp_without_time_zone_Array_5()
{
var arrayMapping = Assert.IsType<NpgsqlArrayTypeMapping>(Source.FindMapping("timestamp(5) without time zone[]"));
Assert.Same(typeof(DateTime[]), arrayMapping.ClrType);
Assert.Equal("timestamp(5) without time zone[]", arrayMapping.StoreType);
var elementMapping = arrayMapping.ElementMapping;
Assert.Same(typeof(DateTime), elementMapping.ClrType);
Assert.Equal("timestamp(5) without time zone", elementMapping.StoreType);
}
[Theory]
[InlineData(typeof(int), "integer")]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册