Skip to content

Commit

Permalink
Annotate for nullability
Browse files Browse the repository at this point in the history
Sync to EFCore 6.0.0-preview.3.21165.3
(3d6009b84224ba009143dfe8e08a4198acdc0afe)

Closes #1552
  • Loading branch information
roji committed Mar 16, 2021
1 parent 731887a commit c3174f5
Show file tree
Hide file tree
Showing 133 changed files with 1,709 additions and 2,289 deletions.
2 changes: 1 addition & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<EFCoreVersion>6.0.0-preview.3.21163.3</EFCoreVersion>
<EFCoreVersion>6.0.0-preview.3.21165.3</EFCoreVersion>
<MicrosoftExtensionsVersion>6.0.0-preview.3.21164.8</MicrosoftExtensionsVersion>
<NpgsqlVersion>6.0.0-ci.20210310T201503</NpgsqlVersion>
</PropertyGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public static class NpgsqlNetTopologySuiteDbContextOptionsBuilderExtensions
/// </returns>
public static NpgsqlDbContextOptionsBuilder UseNetTopologySuite(
[NotNull] this NpgsqlDbContextOptionsBuilder optionsBuilder,
[CanBeNull] CoordinateSequenceFactory coordinateSequenceFactory = null,
[CanBeNull] PrecisionModel precisionModel = null,
[CanBeNull] CoordinateSequenceFactory? coordinateSequenceFactory = null,
[CanBeNull] PrecisionModel? precisionModel = null,
Ordinates handleOrdinates = Ordinates.None,
bool geographyAsDefault = false)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static IServiceCollection AddEntityFrameworkNpgsqlNetTopologySuite(
Check.NotNull(serviceCollection, nameof(serviceCollection));

new EntityFrameworkRelationalServicesBuilder(serviceCollection)
.TryAdd<ISingletonOptions, INpgsqlNetTopologySuiteOptions>(p => p.GetService<INpgsqlNetTopologySuiteOptions>())
.TryAdd<ISingletonOptions, INpgsqlNetTopologySuiteOptions>(p => p.GetRequiredService<INpgsqlNetTopologySuiteOptions>())
.TryAddProviderSpecificServices(
x => x
.TryAddSingletonEnumerable<IRelationalTypeMappingSourcePlugin, NpgsqlNetTopologySuiteTypeMappingSourcePlugin>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal
{
public class NpgsqlNetTopologySuiteOptionsExtension : IDbContextOptionsExtension
{
DbContextOptionsExtensionInfo _info;
DbContextOptionsExtensionInfo? _info;

public virtual bool IsGeographyDefault { get; private set; }

Expand Down Expand Up @@ -61,7 +61,7 @@ public virtual void Validate(IDbContextOptions options)

sealed class ExtensionInfo : DbContextOptionsExtensionInfo
{
string _logFragment;
string? _logFragment;

public ExtensionInfo(IDbContextOptionsExtension extension)
: base(extension)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,20 @@ public NpgsqlGeometryMemberTranslator(
};
}

public virtual SqlExpression Translate(
SqlExpression instance,
public virtual SqlExpression? Translate(
SqlExpression? instance,
MemberInfo member,
Type returnType,
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
{
var declaringType = member.DeclaringType;

if (!typeof(Geometry).IsAssignableFrom(declaringType))
if (instance is null || !typeof(Geometry).IsAssignableFrom(declaringType))
return null;

var typeMapping = instance.TypeMapping;
Debug.Assert(typeMapping != null, "Instance must have typeMapping assigned.");
var storeType = instance.TypeMapping.StoreType;
var resultGeometryTypeMapping = typeof(Geometry).IsAssignableFrom(returnType)
? _typeMappingSource.FindMapping(returnType, storeType)
: null;
var storeType = instance.TypeMapping!.StoreType;

if (typeof(Point).IsAssignableFrom(declaringType))
{
Expand All @@ -108,13 +105,13 @@ public virtual SqlExpression Translate(
return member.Name switch
{
nameof(Geometry.Area) => Function("ST_Area", new[] { instance }, typeof(double)),
nameof(Geometry.Boundary) => Function("ST_Boundary", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Centroid) => Function("ST_Centroid", new[] { instance }, typeof(Point), resultGeometryTypeMapping),
nameof(Geometry.Boundary) => Function("ST_Boundary", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.Centroid) => Function("ST_Centroid", new[] { instance }, typeof(Point), ResultGeometryMapping()),
nameof(GeometryCollection.Count) => Function("ST_NumGeometries", new[] { instance }, typeof(int)),
nameof(Geometry.Dimension) => Function("ST_Dimension", new[] { instance }, typeof(Dimension)),
nameof(LineString.EndPoint) => Function("ST_EndPoint", new[] { instance }, typeof(Point), resultGeometryTypeMapping),
nameof(Geometry.Envelope) => Function("ST_Envelope", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Polygon.ExteriorRing) => Function("ST_ExteriorRing", new[] { instance }, typeof(LineString), resultGeometryTypeMapping),
nameof(LineString.EndPoint) => Function("ST_EndPoint", new[] { instance }, typeof(Point), ResultGeometryMapping()),
nameof(Geometry.Envelope) => Function("ST_Envelope", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Polygon.ExteriorRing) => Function("ST_ExteriorRing", new[] { instance }, typeof(LineString), ResultGeometryMapping()),
nameof(Geometry.GeometryType) => Function("GeometryType", new[] { instance }, typeof(string)),
nameof(LineString.IsClosed) => Function("ST_IsClosed", new[] { instance }, typeof(bool)),
nameof(Geometry.IsEmpty) => Function("ST_IsEmpty", new[] { instance }, typeof(bool)),
Expand All @@ -125,10 +122,10 @@ public virtual SqlExpression Translate(
nameof(Geometry.NumGeometries) => Function("ST_NumGeometries", new[] { instance }, typeof(int)),
nameof(Polygon.NumInteriorRings) => Function("ST_NumInteriorRings", new[] { instance }, typeof(int)),
nameof(Geometry.NumPoints) => Function("ST_NumPoints", new[] { instance }, typeof(int)),
nameof(Geometry.PointOnSurface) => Function("ST_PointOnSurface", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.InteriorPoint) => Function("ST_PointOnSurface", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.PointOnSurface) => Function("ST_PointOnSurface", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.InteriorPoint) => Function("ST_PointOnSurface", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.SRID) => Function("ST_SRID", new[] { instance }, typeof(int)),
nameof(LineString.StartPoint) => Function("ST_StartPoint", new[] { instance }, typeof(Point), resultGeometryTypeMapping),
nameof(LineString.StartPoint) => Function("ST_StartPoint", new[] { instance }, typeof(Point), ResultGeometryMapping()),

nameof(Geometry.OgcGeometryType) => _sqlExpressionFactory.Case(
Function("ST_GeometryType", new[] { instance }, typeof(string)),
Expand All @@ -138,10 +135,16 @@ public virtual SqlExpression Translate(
_ => null
};

SqlFunctionExpression Function(string name, SqlExpression[] arguments, Type returnType, RelationalTypeMapping typeMapping = null)
SqlFunctionExpression Function(string name, SqlExpression[] arguments, Type returnType, RelationalTypeMapping? typeMapping = null)
=> _sqlExpressionFactory.Function(name, arguments,
nullable: true, argumentsPropagateNullability: TrueArrays[arguments.Length],
returnType, typeMapping);

RelationalTypeMapping ResultGeometryMapping()
{
Debug.Assert(typeof(Geometry).IsAssignableFrom(returnType));
return _typeMappingSource.FindMapping(returnType, storeType)!;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ public NpgsqlNetTopologySuiteMethodCallTranslatorPlugin(
/// </summary>
public class NpgsqlGeometryMethodTranslator : IMethodCallTranslator
{
static readonly MethodInfo _collectionItem =
typeof(GeometryCollection).GetRuntimeProperty("Item").GetMethod;
static readonly MethodInfo _collectionItem = typeof(GeometryCollection).GetRuntimeProperty("Item")!.GetMethod!;

readonly ISqlExpressionFactory _sqlExpressionFactory;
readonly IRelationalTypeMappingSource _typeMappingSource;
Expand All @@ -56,19 +55,18 @@ public NpgsqlGeometryMethodTranslator(
}

/// <inheritdoc />
public virtual SqlExpression Translate(
SqlExpression instance,
public virtual SqlExpression? Translate(
SqlExpression? instance,
MethodInfo method,
IReadOnlyList<SqlExpression> arguments,
IDiagnosticsLogger<DbLoggerCategory.Query> logger)
=> typeof(Geometry).IsAssignableFrom(method.DeclaringType)
? TranslateGeometryMethod(instance, method, arguments)
: method.DeclaringType == typeof(NpgsqlNetTopologySuiteDbFunctionsExtensions)
? TranslateDbFunction(instance, method, arguments)
=> method.DeclaringType == typeof(NpgsqlNetTopologySuiteDbFunctionsExtensions)
? TranslateDbFunction(method, arguments)
: instance is not null && typeof(Geometry).IsAssignableFrom(method.DeclaringType)
? TranslateGeometryMethod(instance, method, arguments)
: null;

protected virtual SqlExpression TranslateDbFunction(
[CanBeNull] SqlExpression instance,
private SqlExpression? TranslateDbFunction(
[NotNull] MethodInfo method,
[NotNull] IReadOnlyList<SqlExpression> arguments)
=> method.Name switch
Expand All @@ -89,8 +87,8 @@ protected virtual SqlExpression TranslateDbFunction(
_ => null
};

protected virtual SqlExpression TranslateGeometryMethod(
[CanBeNull] SqlExpression instance,
private SqlExpression? TranslateGeometryMethod(
[NotNull] SqlExpression instance,
[NotNull] MethodInfo method,
[NotNull] IReadOnlyList<SqlExpression> arguments)
{
Expand All @@ -99,9 +97,6 @@ protected virtual SqlExpression TranslateGeometryMethod(

Debug.Assert(typeMapping != null, "At least one argument must have typeMapping.");
var storeType = typeMapping.StoreType;
var resultGeometryTypeMapping = typeof(Geometry).IsAssignableFrom(method.ReturnType)
? _typeMappingSource.FindMapping(method.ReturnType, storeType)
: null;

instance = _sqlExpressionFactory.ApplyTypeMapping(instance, _typeMappingSource.FindMapping(instance.Type, storeType));

Expand All @@ -125,56 +120,62 @@ protected virtual SqlExpression TranslateGeometryMethod(
nullable: true,
argumentsPropagateNullability: TrueArrays[2],
method.ReturnType,
_typeMappingSource.FindMapping(typeof(Geometry), instance.TypeMapping.StoreType));
_typeMappingSource.FindMapping(typeof(Geometry), instance.TypeMapping!.StoreType));
}

return method.Name switch
{
nameof(Geometry.AsBinary) => Function("ST_AsBinary", new[] { instance }, typeof(byte[])),
nameof(Geometry.AsText) => Function("ST_AsText", new[] { instance }, typeof(string)),
nameof(Geometry.Buffer) => Function("ST_Buffer", new[] { instance }.Concat(arguments).ToArray(), typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Buffer) => Function("ST_Buffer", new[] { instance }.Concat(arguments).ToArray(), typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.Contains) => Function("ST_Contains", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.ConvexHull) => Function("ST_ConvexHull", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.ConvexHull) => Function("ST_ConvexHull", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.CoveredBy) => Function("ST_CoveredBy", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.Covers) => Function("ST_Covers", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.Crosses) => Function("ST_Crosses", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.Disjoint) => Function("ST_Disjoint", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.Difference) => Function("ST_Difference", new[] { instance, arguments[0] }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Difference) => Function("ST_Difference", new[] { instance, arguments[0] }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.Distance) => Function("ST_Distance", new[] { instance }.Concat(arguments).ToArray(), typeof(double)),
nameof(Geometry.EqualsExact) => Function("ST_OrderingEquals", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.EqualsTopologically) => Function("ST_Equals", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.GetGeometryN) => Function("ST_GeometryN", new[] { instance, OneBased(arguments[0]) }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Polygon.GetInteriorRingN) => Function("ST_InteriorRingN", new[] { instance, OneBased(arguments[0]) }, typeof(Geometry), resultGeometryTypeMapping),
nameof(LineString.GetPointN) => Function("ST_PointN", new[] { instance, OneBased(arguments[0]) }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Intersection) => Function("ST_Intersection", new[] { instance, arguments[0] }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.GetGeometryN) => Function("ST_GeometryN", new[] { instance, OneBased(arguments[0]) }, typeof(Geometry), ResultGeometryMapping()),
nameof(Polygon.GetInteriorRingN) => Function("ST_InteriorRingN", new[] { instance, OneBased(arguments[0]) }, typeof(Geometry), ResultGeometryMapping()),
nameof(LineString.GetPointN) => Function("ST_PointN", new[] { instance, OneBased(arguments[0]) }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.Intersection) => Function("ST_Intersection", new[] { instance, arguments[0] }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.Intersects) => Function("ST_Intersects", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.IsWithinDistance) => Function("ST_DWithin", new[] { instance }.Concat(arguments).ToArray(), typeof(bool)),
nameof(Geometry.Normalized) => Function("ST_Normalize", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Normalized) => Function("ST_Normalize", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.Overlaps) => Function("ST_Overlaps", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.Relate) => Function("ST_Relate", new[] { instance, arguments[0], arguments[1] }, typeof(bool)),
nameof(Geometry.Reverse) => Function("ST_Reverse", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.SymmetricDifference) => Function("ST_SymDifference", new[] { instance, arguments[0] }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Reverse) => Function("ST_Reverse", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.SymmetricDifference) => Function("ST_SymDifference", new[] { instance, arguments[0] }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.ToBinary) => Function("ST_AsBinary", new[] { instance }, typeof(byte[])),
nameof(Geometry.ToText) => Function("ST_AsText", new[] { instance }, typeof(string)),
nameof(Geometry.Touches) => Function("ST_Touches", new[] { instance, arguments[0] }, typeof(bool)),
nameof(Geometry.Within) => Function("ST_Within", new[] { instance, arguments[0] }, typeof(bool)),

nameof(Geometry.Union) when arguments.Count == 0 => Function("ST_UnaryUnion", new[] { instance }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Union) when arguments.Count == 1 => Function("ST_Union", new[] { instance, arguments[0] }, typeof(Geometry), resultGeometryTypeMapping),
nameof(Geometry.Union) when arguments.Count == 0 => Function("ST_UnaryUnion", new[] { instance }, typeof(Geometry), ResultGeometryMapping()),
nameof(Geometry.Union) when arguments.Count == 1 => Function("ST_Union", new[] { instance, arguments[0] }, typeof(Geometry), ResultGeometryMapping()),

_ => null
};

SqlFunctionExpression Function(string name, SqlExpression[] arguments, Type returnType, RelationalTypeMapping typeMapping = null)
SqlFunctionExpression Function(string name, SqlExpression[] arguments, Type returnType, RelationalTypeMapping? typeMapping = null)
=> _sqlExpressionFactory.Function(name, arguments,
nullable: true, argumentsPropagateNullability: TrueArrays[arguments.Length],
returnType, typeMapping);

// NetTopologySuite uses 0-based indexing, but PostGIS uses 1-based
SqlExpression OneBased(SqlExpression arg)
=> arg is SqlConstantExpression constant
? _sqlExpressionFactory.Constant((int)constant.Value + 1, constant.TypeMapping)
? _sqlExpressionFactory.Constant((int)constant.Value! + 1, constant.TypeMapping)
: (SqlExpression)_sqlExpressionFactory.Add(arg, _sqlExpressionFactory.Constant(1));

RelationalTypeMapping ResultGeometryMapping()
{
Debug.Assert(typeof(Geometry).IsAssignableFrom(method.ReturnType));
return _typeMappingSource.FindMapping(method.ReturnType, storeType)!;
}
}
}
}
Loading

0 comments on commit c3174f5

Please sign in to comment.