From a1b716323fd361130ad438a852bb65a891f40395 Mon Sep 17 00:00:00 2001 From: Peet Whittaker Date: Fri, 19 Jan 2024 15:44:12 +0000 Subject: [PATCH] Add spatial dialect for MySQL 8 #93 --- .github/workflows/ci.yml | 8 + .../Dialect/MySQL57SpatialDialect.cs | 26 ++- .../Dialect/MySQL80SpatialDialect.cs | 148 ++++++++++++++++++ ...ometryColumn.MySQL80SpatialDialect.hbm.xml | 19 +++ ...erenceSystem.MySQL80SpatialDialect.hbm.xml | 17 ++ .../NHibernate.Spatial.MySQL.csproj | 5 + ...terType.cs => MySQLGeometryAdapterType.cs} | 4 +- ...57GeometryType.cs => MySQLGeometryType.cs} | 8 +- NHibernate.Spatial.sln | 6 + README.md | 13 +- .../MySQL57CriteriaFixture.cs | 15 -- .../MySQL57SpatialQueriesFixture.cs | 12 +- .../MySQL80ConformanceItemsFixture.cs | 51 ++++++ .../MySQL80CriteriaFixture.cs | 14 ++ .../MySQL80NtsTestCasesFixture.cs | 52 ++++++ .../MySQL80ProjectionsFixture.cs | 14 ++ .../MySQL80SpatialQueriesFixture.cs | 104 ++++++++++++ .../NtsTestCases/Model/NtsTestCase.cs | 73 +++++++++ .../NtsTestCases/Model/NtsTestCase.hbm.xml | 32 ++++ .../Model/LineStringEntity.cs | 49 ++++++ .../Model/LineStringEntity.hbm.xml | 16 ++ .../Model/MultiLineStringEntity.cs | 49 ++++++ .../Model/MultiLineStringEntity.hbm.xml | 16 ++ .../Model/MultiPointEntity.cs | 49 ++++++ .../Model/MultiPointEntity.hbm.xml | 16 ++ .../Model/MultiPolygonEntity.cs | 49 ++++++ .../Model/MultiPolygonEntity.hbm.xml | 16 ++ .../RandomGeometries/Model/PointEntity.cs | 49 ++++++ .../Model/PointEntity.hbm.xml | 16 ++ .../RandomGeometries/Model/PolygonEntity.cs | 49 ++++++ .../Model/PolygonEntity.hbm.xml | 16 ++ .../TestConfiguration.cs | 34 ++++ .../Tests.NHibernate.Spatial.MySQL80.csproj | 39 +++++ .../appsettings.json | 5 + .../initdb/nhsp_test.sql | 14 ++ .../ConformanceItemsFixture.cs | 6 +- .../RandomGeometries/DataGenerator.cs | 14 +- .../RandomGeometries/SpatialQueriesFixture.cs | 59 +++---- docker-compose.yml | 9 ++ 39 files changed, 1101 insertions(+), 90 deletions(-) create mode 100644 NHibernate.Spatial.MySQL/Dialect/MySQL80SpatialDialect.cs create mode 100644 NHibernate.Spatial.MySQL/Metadata/GeometryColumn.MySQL80SpatialDialect.hbm.xml create mode 100644 NHibernate.Spatial.MySQL/Metadata/SpatialReferenceSystem.MySQL80SpatialDialect.hbm.xml rename NHibernate.Spatial.MySQL/Type/{MySQL57GeometryAdapterType.cs => MySQLGeometryAdapterType.cs} (96%) rename NHibernate.Spatial.MySQL/Type/{MySQL57GeometryType.cs => MySQLGeometryType.cs} (90%) create mode 100644 Tests.NHibernate.Spatial.MySQL80/MySQL80ConformanceItemsFixture.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/MySQL80CriteriaFixture.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/MySQL80NtsTestCasesFixture.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/MySQL80ProjectionsFixture.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/MySQL80SpatialQueriesFixture.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.hbm.xml create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.hbm.xml create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.hbm.xml create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.hbm.xml create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.hbm.xml create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.hbm.xml create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.hbm.xml create mode 100644 Tests.NHibernate.Spatial.MySQL80/TestConfiguration.cs create mode 100644 Tests.NHibernate.Spatial.MySQL80/Tests.NHibernate.Spatial.MySQL80.csproj create mode 100644 Tests.NHibernate.Spatial.MySQL80/appsettings.json create mode 100644 Tests.NHibernate.Spatial.MySQL80/initdb/nhsp_test.sql diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c908fc..47ec9e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,14 @@ jobs: DB_INIT: docker run -d -e MYSQL_ROOT_PASSWORD=nhsp_test -p 13306:3306 -v ./Tests.NHibernate.Spatial.MySQL57/initdb:/docker-entrypoint-initdb.d mysql:5.7-debian TEST_PROJECT: Tests.NHibernate.Spatial.MySQL57 + - DB: MySQL80 (MySQL 8.0) + DB_INIT: docker run -d -e MYSQL_ROOT_PASSWORD=nhsp_test -p 13307:3306 -v ./Tests.NHibernate.Spatial.MySQL80/initdb:/docker-entrypoint-initdb.d mysql:8.0 + TEST_PROJECT: Tests.NHibernate.Spatial.MySQL80 + + - DB: MySQL80 (MySQL 8.3) + DB_INIT: docker run -d -e MYSQL_ROOT_PASSWORD=nhsp_test -p 13307:3306 -v ./Tests.NHibernate.Spatial.MySQL80/initdb:/docker-entrypoint-initdb.d mysql:8.3 + TEST_PROJECT: Tests.NHibernate.Spatial.MySQL80 + - DB: PostGis20 (PostgreSQL 12 PostGIS 2.5) DB_INIT: docker run -d -e POSTGRES_PASSWORD=nhsp_test -p 15432:5432 -v ./Tests.NHibernate.Spatial.PostGis20/initdb:/docker-entrypoint-initdb.d postgis/postgis:12-2.5 TEST_PROJECT: Tests.NHibernate.Spatial.PostGis20 diff --git a/NHibernate.Spatial.MySQL/Dialect/MySQL57SpatialDialect.cs b/NHibernate.Spatial.MySQL/Dialect/MySQL57SpatialDialect.cs index 25a4ac4..88b0412 100644 --- a/NHibernate.Spatial.MySQL/Dialect/MySQL57SpatialDialect.cs +++ b/NHibernate.Spatial.MySQL/Dialect/MySQL57SpatialDialect.cs @@ -33,7 +33,7 @@ namespace NHibernate.Spatial.Dialect public class MySQL57SpatialDialect : MySQL5Dialect, ISpatialDialect { protected const string DialectPrefix = SpatialDialect.IsoPrefix; - protected static readonly IType geometryType = new CustomType(typeof(MySQL57GeometryType), null); + private static readonly IType geometryType = new CustomType(typeof(MySQLGeometryType), null); /// /// Initializes a new instance of the class. @@ -125,7 +125,7 @@ protected override void RegisterFunctions() RegisterSpatialFunction("GeometryType", NHibernateUtil.String); RegisterSpatialFunction("Area", NHibernateUtil.Double); - RegisterSpatialFunction("Length", "GLength", NHibernateUtil.Double); + RegisterSpatialFunction("Length", NHibernateUtil.Double); RegisterSpatialFunction("X", NHibernateUtil.Double); RegisterSpatialFunction("Y", NHibernateUtil.Double); @@ -150,12 +150,12 @@ protected void RegisterSpatialFunction(string standardName, string dialectName, protected void RegisterSpatialFunction(string name, IType returnedType, int allowedArgsCount) { - RegisterSpatialFunction(name, name, returnedType, allowedArgsCount); + RegisterSpatialFunction(name, SpatialDialect.IsoPrefix + name, returnedType, allowedArgsCount); } protected void RegisterSpatialFunction(string name, IType returnedType) { - RegisterSpatialFunction(name, name, returnedType); + RegisterSpatialFunction(name, SpatialDialect.IsoPrefix + name, returnedType); } protected void RegisterSpatialFunction(string name, int allowedArgsCount) @@ -193,7 +193,7 @@ protected void RegisterSpatialFunction(SpatialAnalysis analysis) /// public virtual IGeometryUserType CreateGeometryUserType() { - return new MySQL57GeometryType(); + return new MySQLGeometryType(); } /// @@ -208,15 +208,9 @@ public virtual IGeometryUserType CreateGeometryUserType() /// The geometry. /// The srid. /// - public SqlString GetSpatialTransformString(object geometry, int srid) + public virtual SqlString GetSpatialTransformString(object geometry, int srid) { - return new SqlStringBuilder() - .Add("Transform(") - .AddObject(geometry) - .Add(",") - .Add(srid.ToString()) - .Add(")") - .ToSqlString(); + throw new NotSupportedException("MySQL 5.7 does not support spatial transform"); } /// @@ -491,7 +485,7 @@ public string GetSpatialCreateString(string schema) /// /// The schema. /// - private string QuoteSchema(string schema) + protected string QuoteSchema(string schema) { if (string.IsNullOrEmpty(schema)) { @@ -511,7 +505,7 @@ private string QuoteSchema(string schema) /// The dimension. /// Whether or not the column is nullable /// - public string GetSpatialCreateString(string schema, string table, string column, int srid, string subtype, int dimension, bool isNullable) + public virtual string GetSpatialCreateString(string schema, string table, string column, int srid, string subtype, int dimension, bool isNullable) { var builder = new StringBuilder(); @@ -568,7 +562,7 @@ public string GetSpatialDropString(string schema, string table, string column) /// /// true if it supports spatial metadata; otherwise, false. /// - public bool SupportsSpatialMetadata(MetadataClass metadataClass) + public virtual bool SupportsSpatialMetadata(MetadataClass metadataClass) { return false; } diff --git a/NHibernate.Spatial.MySQL/Dialect/MySQL80SpatialDialect.cs b/NHibernate.Spatial.MySQL/Dialect/MySQL80SpatialDialect.cs new file mode 100644 index 0000000..5611cc3 --- /dev/null +++ b/NHibernate.Spatial.MySQL/Dialect/MySQL80SpatialDialect.cs @@ -0,0 +1,148 @@ +using NHibernate.Spatial.Metadata; +using NHibernate.SqlCommand; +using System; +using System.Data; +using System.Text; + +namespace NHibernate.Spatial.Dialect +{ + public class MySQL80SpatialDialect : MySQL57SpatialDialect + { + public MySQL80SpatialDialect() + { + // See: https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Dialect/MySQL8Dialect.cs#L7C48-L7C73 + RegisterColumnType(DbType.Boolean, "BOOLEAN"); + } + + /// + /// Gets the spatial transform string. + /// + /// The geometry. + /// The srid. + /// + public override SqlString GetSpatialTransformString(object geometry, int srid) + { + return new SqlStringBuilder() + .Add(DialectPrefix) + .Add("Transform(") + .AddObject(geometry) + .Add(",") + .Add(srid.ToString()) + .Add(")") + .ToSqlString(); + } + + /// + /// Gets the spatial validation string. + /// + /// The geometry. + /// The validation. + /// if set to true [criterion]. + /// + public override SqlString GetSpatialValidationString(object geometry, SpatialValidation validation, bool criterion) + { + return new SqlStringBuilder() + .Add(DialectPrefix) + .Add(validation.ToString()) + .Add("(") + .AddObject(geometry) + .Add(")") + .ToSqlString(); + } + + /// + /// Gets the spatial aggregate string. + /// + /// The geometry. + /// The aggregate. + /// + public override SqlString GetSpatialAggregateString(object geometry, SpatialAggregate aggregate) + { + switch (aggregate) + { + case SpatialAggregate.Collect: + return new SqlStringBuilder() + .Add(DialectPrefix) + .Add(aggregate.ToString()) + .Add("(") + .AddObject(geometry) + .Add(")") + .ToSqlString(); + + case SpatialAggregate.ConvexHull: + case SpatialAggregate.Envelope: + // MySQL only directly supports the ST_Collect spatial aggregate function, therefore + // we mimic these spatial agg functions by grouping the geometries from each row into + // a geometry collection and then performing the function on the geometry collection + // See: https://forums.mysql.com/read.php?23,249284,249284#msg-249284 + var collectAggregate = GetSpatialAggregateString(geometry, SpatialAggregate.Collect); + return new SqlStringBuilder() + .Add(DialectPrefix) + .Add(aggregate.ToString()) + .Add("(") + .Add(collectAggregate) + .Add(")") + .ToSqlString(); + + case SpatialAggregate.Intersection: + case SpatialAggregate.Union: + throw new NotSupportedException($"MySQL does not support {aggregate} spatial aggregate function"); + + default: + throw new ArgumentException("Invalid spatial aggregate argument"); + } + } + + /// + /// Gets the spatial create string. + /// + /// The schema. + /// The table. + /// The column. + /// The srid. + /// The subtype. + /// The dimension. + /// Whether or not the column is nullable + /// + public override string GetSpatialCreateString(string schema, string table, string column, int srid, string subtype, int dimension, bool isNullable) + { + var builder = new StringBuilder(); + + string quotedSchema = QuoteSchema(schema); + string quoteForTableName = QuoteForTableName(table); + string quoteForColumnName = QuoteForColumnName(column); + + builder.AppendFormat("ALTER TABLE {0}{1} DROP COLUMN {2}" + , quotedSchema + , quoteForTableName + , quoteForColumnName + ); + + builder.Append(MultipleQueriesSeparator); + + builder.AppendFormat("ALTER TABLE {0}{1} ADD {2} {3} {4} SRID {5}" + , quotedSchema + , quoteForTableName + , quoteForColumnName + , subtype + , isNullable ? "NULL" : "NOT NULL" + , srid + ); + + builder.Append(MultipleQueriesSeparator); + + return builder.ToString(); + } + + /// + /// Gets a value indicating whether it supports spatial metadata. + /// + /// + /// true if it supports spatial metadata; otherwise, false. + /// + public override bool SupportsSpatialMetadata(MetadataClass metadataClass) + { + return true; + } + } +} diff --git a/NHibernate.Spatial.MySQL/Metadata/GeometryColumn.MySQL80SpatialDialect.hbm.xml b/NHibernate.Spatial.MySQL/Metadata/GeometryColumn.MySQL80SpatialDialect.hbm.xml new file mode 100644 index 0000000..1518b03 --- /dev/null +++ b/NHibernate.Spatial.MySQL/Metadata/GeometryColumn.MySQL80SpatialDialect.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + diff --git a/NHibernate.Spatial.MySQL/Metadata/SpatialReferenceSystem.MySQL80SpatialDialect.hbm.xml b/NHibernate.Spatial.MySQL/Metadata/SpatialReferenceSystem.MySQL80SpatialDialect.hbm.xml new file mode 100644 index 0000000..d8e85bd --- /dev/null +++ b/NHibernate.Spatial.MySQL/Metadata/SpatialReferenceSystem.MySQL80SpatialDialect.hbm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/NHibernate.Spatial.MySQL/NHibernate.Spatial.MySQL.csproj b/NHibernate.Spatial.MySQL/NHibernate.Spatial.MySQL.csproj index 14e3390..205b5f3 100644 --- a/NHibernate.Spatial.MySQL/NHibernate.Spatial.MySQL.csproj +++ b/NHibernate.Spatial.MySQL/NHibernate.Spatial.MySQL.csproj @@ -9,6 +9,11 @@ snupkg + + + + + diff --git a/NHibernate.Spatial.MySQL/Type/MySQL57GeometryAdapterType.cs b/NHibernate.Spatial.MySQL/Type/MySQLGeometryAdapterType.cs similarity index 96% rename from NHibernate.Spatial.MySQL/Type/MySQL57GeometryAdapterType.cs rename to NHibernate.Spatial.MySQL/Type/MySQLGeometryAdapterType.cs index 7506dcc..e4a53e2 100644 --- a/NHibernate.Spatial.MySQL/Type/MySQL57GeometryAdapterType.cs +++ b/NHibernate.Spatial.MySQL/Type/MySQLGeometryAdapterType.cs @@ -30,9 +30,9 @@ namespace NHibernate.Spatial.Type /// This class maps MySQLDbType.Geometry to and from Geometry /// [Serializable] - public class MySQL57GeometryAdapterType : ImmutableType + public class MySQLGeometryAdapterType : ImmutableType { - public MySQL57GeometryAdapterType() + public MySQLGeometryAdapterType() : base(SqlTypeFactory.Byte) // Any arbitrary type can be passed as parameter { } diff --git a/NHibernate.Spatial.MySQL/Type/MySQL57GeometryType.cs b/NHibernate.Spatial.MySQL/Type/MySQLGeometryType.cs similarity index 90% rename from NHibernate.Spatial.MySQL/Type/MySQL57GeometryType.cs rename to NHibernate.Spatial.MySQL/Type/MySQLGeometryType.cs index cc93d43..643877f 100644 --- a/NHibernate.Spatial.MySQL/Type/MySQL57GeometryType.cs +++ b/NHibernate.Spatial.MySQL/Type/MySQLGeometryType.cs @@ -26,12 +26,12 @@ namespace NHibernate.Spatial.Type /// /// MySQL geometry type (to be used in models) that supports the changes introduced in MySQL 5.7 /// - public class MySQL57GeometryType : GeometryTypeBase + public class MySQLGeometryType : GeometryTypeBase { - private static readonly NullableType MySQL57GeometryAdapterType = new MySQL57GeometryAdapterType(); + private static readonly NullableType MySQLGeometryAdapterType = new MySQLGeometryAdapterType(); - public MySQL57GeometryType() - : base(MySQL57GeometryAdapterType) + public MySQLGeometryType() + : base(MySQLGeometryAdapterType) { } protected override void SetDefaultSRID(Geometry geometry) diff --git a/NHibernate.Spatial.sln b/NHibernate.Spatial.sln index f888414..c0c81a5 100644 --- a/NHibernate.Spatial.sln +++ b/NHibernate.Spatial.sln @@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution NHibernate.Spatial.props = NHibernate.Spatial.props EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.NHibernate.Spatial.MySQL80", "Tests.NHibernate.Spatial.MySQL80\Tests.NHibernate.Spatial.MySQL80.csproj", "{D6643E3E-D004-41A7-B1AB-96D52018FE17}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -68,6 +70,10 @@ Global {12E29E47-4760-427E-8EF9-5D2F39B0E980}.Debug|Any CPU.Build.0 = Debug|Any CPU {12E29E47-4760-427E-8EF9-5D2F39B0E980}.Release|Any CPU.ActiveCfg = Release|Any CPU {12E29E47-4760-427E-8EF9-5D2F39B0E980}.Release|Any CPU.Build.0 = Release|Any CPU + {D6643E3E-D004-41A7-B1AB-96D52018FE17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6643E3E-D004-41A7-B1AB-96D52018FE17}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6643E3E-D004-41A7-B1AB-96D52018FE17}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6643E3E-D004-41A7-B1AB-96D52018FE17}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 31dc0ca..9599c2f 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,11 @@ NHibernate binaries. ## Supported Databases -| Package | Minimum Version | CI Tests | -|----------------------------|-------------------------------------------|---------------------------------------------------| -| NHibernate.Spatial.MsSql | SQL Server 2012 | SQL Server 2017, SQL Server 2019, SQL Server 2022 | -| NHibernate.Spatial.MySQL | MySQL 5.7 | MySQL 5.7 | -| NHibernate.Spatial.PostGis | PostgreSQL 12 w/ PostGIS 2.5 1 | PostgreSQL 12 w/ PostGIS 2.5 | - -1 PostgreSQL 9.1 w/ PostGIS 2.0 or later will likely work, but are not explicitly -supported here as they are EOL (see [here](https://trac.osgeo.org/postgis/wiki/UsersWikiPostgreSQLPostGIS#PostGISSupportMatrix)). +| Package | Dialects | CI Tests | +|----------------------------|--------------------------|---------------------------------------------------| +| NHibernate.Spatial.MsSql | SQL Server 2012 | SQL Server 2017, SQL Server 2019, SQL Server 2022 | +| NHibernate.Spatial.MySQL | MySQL 5.7, MySQL 8.0 | MySQL 5.7, MySQL 8.0, MySQL 8.3 | +| NHibernate.Spatial.PostGis | PostGIS 2.0 | PostGIS 2.5 (PostgreSQL 12) | ## Getting Started diff --git a/Tests.NHibernate.Spatial.MySQL57/MySQL57CriteriaFixture.cs b/Tests.NHibernate.Spatial.MySQL57/MySQL57CriteriaFixture.cs index eddf2a2..05bc2c5 100644 --- a/Tests.NHibernate.Spatial.MySQL57/MySQL57CriteriaFixture.cs +++ b/Tests.NHibernate.Spatial.MySQL57/MySQL57CriteriaFixture.cs @@ -6,21 +6,6 @@ namespace Tests.NHibernate.Spatial [TestFixture] public class MySQL57CriteriaFixture : CriteriaFixture { - [Test] - [Ignore("Empty geometry collections not supported by MySql.Data.Types.MySqlGeometry")] - public override void CountNull() - { } - - [Test] - [Ignore("Empty geometry collections not supported by MySql.Data.Types.MySqlGeometry")] - public override void CountSpatialEmpty() - { } - - [Test] - [Ignore("Empty geometry collections not supported by MySql.Data.Types.MySqlGeometry")] - public override void IsDirty() - { } - protected override void Configure(Configuration configuration) { TestConfiguration.Configure(configuration); diff --git a/Tests.NHibernate.Spatial.MySQL57/MySQL57SpatialQueriesFixture.cs b/Tests.NHibernate.Spatial.MySQL57/MySQL57SpatialQueriesFixture.cs index 1ea74a3..eac6d9d 100644 --- a/Tests.NHibernate.Spatial.MySQL57/MySQL57SpatialQueriesFixture.cs +++ b/Tests.NHibernate.Spatial.MySQL57/MySQL57SpatialQueriesFixture.cs @@ -63,8 +63,8 @@ WHERE the_geom IS NOT NULL protected override ISQLQuery SqlIsEmptyLineString(ISession session) { - return session.CreateSQLQuery(@" -SELECT IsEmpty(the_geom) as result + return session.CreateSQLQuery($@" +SELECT {SpatialDialect.IsoPrefix}IsEmpty(the_geom) as result FROM linestringtest WHERE oid = ? AND the_geom IS NOT NULL @@ -74,8 +74,8 @@ AND the_geom IS NOT NULL protected override ISQLQuery SqlIsSimpleLineString(ISession session) { - return session.CreateSQLQuery(@" -SELECT IsSimple(the_geom) as result + return session.CreateSQLQuery($@" +SELECT {SpatialDialect.IsoPrefix}IsSimple(the_geom) as result FROM linestringtest WHERE oid = ? AND the_geom IS NOT NULL @@ -85,8 +85,8 @@ AND the_geom IS NOT NULL protected override ISQLQuery SqlAsBinaryLineString(ISession session) { - return session.CreateSQLQuery(@" -SELECT AsBinary(the_geom) as result + return session.CreateSQLQuery($@" +SELECT {SpatialDialect.IsoPrefix}AsBinary(the_geom) as result FROM linestringtest WHERE oid = ? AND the_geom IS NOT NULL diff --git a/Tests.NHibernate.Spatial.MySQL80/MySQL80ConformanceItemsFixture.cs b/Tests.NHibernate.Spatial.MySQL80/MySQL80ConformanceItemsFixture.cs new file mode 100644 index 0000000..bcee69b --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/MySQL80ConformanceItemsFixture.cs @@ -0,0 +1,51 @@ +using NHibernate.Cfg; +using NUnit.Framework; + +namespace Tests.NHibernate.Spatial +{ + [TestFixture] + public class MySQL80ConformanceItemsFixture : MySQL57ConformanceItemsFixture + { + protected override string SpatialReferenceSystemWKT => @"PROJCS[""WGS 72 / UTM zone 14N"",GEOGCS[""WGS 72"",DATUM[""World Geodetic System 1972"",SPHEROID[""WGS 72"",6378135,298.26,AUTHORITY[""EPSG"",""7043""]],TOWGS84[0,0,4.5,0,0,0.554,0.219],AUTHORITY[""EPSG"",""6322""]],PRIMEM[""Greenwich"",0,AUTHORITY[""EPSG"",""8901""]],UNIT[""degree"",0.017453292519943278,AUTHORITY[""EPSG"",""9122""]],AXIS[""Lat"",NORTH],AXIS[""Lon"",EAST],AUTHORITY[""EPSG"",""4322""]],PROJECTION[""Transverse Mercator"",AUTHORITY[""EPSG"",""9807""]],PARAMETER[""Latitude of natural origin"",0,AUTHORITY[""EPSG"",""8801""]],PARAMETER[""Longitude of natural origin"",-99,AUTHORITY[""EPSG"",""8802""]],PARAMETER[""Scale factor at natural origin"",0.9996,AUTHORITY[""EPSG"",""8805""]],PARAMETER[""False easting"",500000,AUTHORITY[""EPSG"",""8806""]],PARAMETER[""False northing"",0,AUTHORITY[""EPSG"",""8807""]],UNIT[""metre"",1,AUTHORITY[""EPSG"",""9001""]],AXIS[""E"",EAST],AXIS[""N"",NORTH],AUTHORITY[""EPSG"",""32214""]]"; + + [Test] + [Ignore("The ST_GEOMETRY_COLUMNS view in MySQL 8 does not include geometry dimension")] + public override void ConformanceItemT03Hql() + { } + + [Test] + [Ignore("The ST_GEOMETRY_COLUMNS view in MySQL 8 does not include geometry dimension")] + public override void ConformanceItemT03Linq() + { } + + protected override void Configure(Configuration configuration) + { + TestConfiguration.Configure(configuration); + } + + protected override void OnBeforeCreateSchema() + { + using (var session = sessions.OpenSession()) + { + var query = session.CreateSQLQuery("CREATE SPATIAL REFERENCE SYSTEM :srs_id NAME 'Test' ORGANIZATION :org_name IDENTIFIED BY :org_srs_id DEFINITION :definition") + .SetParameter("srs_id", 101) + .SetParameter("org_name", "POSC") + .SetParameter("org_srs_id", 32214) + .SetParameter("definition", SpatialReferenceSystemWKT); + + query.ExecuteUpdate(); + } + } + + protected override void OnAfterDropSchema() + { + using (var session = sessions.OpenSession()) + { + var query = session.CreateSQLQuery("DROP SPATIAL REFERENCE SYSTEM :srs_id") + .SetParameter("srs_id", 101); + + query.ExecuteUpdate(); + } + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/MySQL80CriteriaFixture.cs b/Tests.NHibernate.Spatial.MySQL80/MySQL80CriteriaFixture.cs new file mode 100644 index 0000000..c39c498 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/MySQL80CriteriaFixture.cs @@ -0,0 +1,14 @@ +using NHibernate.Cfg; +using NUnit.Framework; + +namespace Tests.NHibernate.Spatial +{ + [TestFixture] + public class MySQL80CriteriaFixture : MySQL57CriteriaFixture + { + protected override void Configure(Configuration configuration) + { + TestConfiguration.Configure(configuration); + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/MySQL80NtsTestCasesFixture.cs b/Tests.NHibernate.Spatial.MySQL80/MySQL80NtsTestCasesFixture.cs new file mode 100644 index 0000000..b17016a --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/MySQL80NtsTestCasesFixture.cs @@ -0,0 +1,52 @@ +using System; +using NHibernate.Cfg; +using NUnit.Framework; +using Tests.NHibernate.Spatial.NtsTestCases; +using Tests.NHibernate.Spatial.NtsTestCases.Model; + +namespace Tests.NHibernate.Spatial +{ + [TestFixture] + public class MySQL80NtsTestCasesFixture : NtsTestCasesFixture + { + protected override Type[] Mappings + { + get + { + return new[] + { + typeof(NtsTestCase) + }; + } + } + + protected override void Configure(Configuration configuration) + { + TestConfiguration.Configure(configuration); + } + + #region Unsupported features + + [Test] + [Ignore("Provider does not support the Relate function")] + public override void BooleanRelate() + { } + + [Test] + [Ignore("Provider does not support the CoveredBy function")] + public override void CoveredBy() + { } + + [Test] + [Ignore("Provider does not support the Covers function")] + public override void Covers() + { } + + [Test] + [Ignore("Provider does not support the Relate function")] + public override void StringRelate() + { } + + #endregion + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/MySQL80ProjectionsFixture.cs b/Tests.NHibernate.Spatial.MySQL80/MySQL80ProjectionsFixture.cs new file mode 100644 index 0000000..673989b --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/MySQL80ProjectionsFixture.cs @@ -0,0 +1,14 @@ +using NHibernate.Cfg; +using NUnit.Framework; + +namespace Tests.NHibernate.Spatial +{ + [TestFixture] + public class MySQL80ProjectionsFixture : MySQL57ProjectionsFixture + { + protected override void Configure(Configuration configuration) + { + TestConfiguration.Configure(configuration); + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/MySQL80SpatialQueriesFixture.cs b/Tests.NHibernate.Spatial.MySQL80/MySQL80SpatialQueriesFixture.cs new file mode 100644 index 0000000..4fc171c --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/MySQL80SpatialQueriesFixture.cs @@ -0,0 +1,104 @@ +using System; +using NHibernate.Cfg; +using NHibernate.Spatial.Dialect; +using NUnit.Framework; +using Tests.NHibernate.Spatial.RandomGeometries; +using Tests.NHibernate.Spatial.RandomGeometries.Model; + +namespace Tests.NHibernate.Spatial +{ + [TestFixture] + public class MySQL80SpatialQueriesFixture : MySQL57SpatialQueriesFixture + { + protected override Type[] Mappings + { + get + { + return new[] + { + typeof(LineStringEntity), + typeof(MultiLineStringEntity), + typeof(MultiPointEntity), + typeof(MultiPolygonEntity), + typeof(PointEntity), + typeof(PolygonEntity), + }; + } + } + + [Test] + public override void HqlSRID() + { + var results = Session + .CreateQuery("select NHSP.SRID(l.Geometry) from LineStringEntity as l where l.Geometry is not null") + .List(); + + foreach (object item in results) + { + int srid = (int) item; + Assert.AreEqual(0, srid); + } + } + + protected override string SqlLineStringFilter(string filterString) + { + return $@" +SELECT count(*) +FROM linestringtest +WHERE MBRIntersects(the_geom, {SpatialDialect.IsoPrefix}GeomFromText('{filterString}', 0)) +"; + } + + protected override string SqlPolygonFilter(string filterString) + { + return $@" +SELECT count(*) +FROM polygontest +WHERE MBRIntersects(the_geom, {SpatialDialect.IsoPrefix}GeomFromText('{filterString}', 0)) +"; + } + + protected override string SqlMultiLineStringFilter(string filterString) + { + return $@" +SELECT count(*) +FROM multilinestringtest +WHERE MBRIntersects(the_geom, {SpatialDialect.IsoPrefix}GeomFromText('{filterString}', 0)) +"; + } + + protected override string SqlOvelapsLineString(string filterString) + { + return $@" +SELECT count(*) +FROM linestringtest +WHERE the_geom IS NOT NULL +AND {SpatialDialect.IsoPrefix}Overlaps({SpatialDialect.IsoPrefix}PolygonFromText('{filterString}', 0), the_geom) +"; + } + + protected override string SqlIntersectsLineString(string filterString) + { + return $@" +SELECT count(*) +FROM linestringtest +WHERE the_geom IS NOT NULL +AND {SpatialDialect.IsoPrefix}Intersects({SpatialDialect.IsoPrefix}PolygonFromText('{filterString}', 0), the_geom) +"; + } + + protected override void Configure(Configuration configuration) + { + TestConfiguration.Configure(configuration); + } + + protected override void OnTestFixtureSetUp() + { + const int srid = 0; + DataGenerator.Generate(sessions, srid); + + Filter = Wkt.Read(FilterString); + Filter.SRID = srid; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.cs b/Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.cs new file mode 100644 index 0000000..0c7c750 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.cs @@ -0,0 +1,73 @@ +using NetTopologySuite.Geometries; +using System; + +namespace Tests.NHibernate.Spatial.NtsTestCases.Model +{ + [Serializable] + public class NtsTestCase + { + private long id; + + private string description; + + private Geometry geometryA = GeometryCollection.Empty; + + private Geometry geometryB = GeometryCollection.Empty; + + private string operation; + + private string relatePattern; + + private Geometry geometryResult = GeometryCollection.Empty; + + private bool booleanResult; + + public virtual long Id + { + get => id; + set => id = value; + } + + public virtual string Description + { + get => description; + set => description = value; + } + + public virtual Geometry GeometryA + { + get => geometryA; + set => geometryA = value; + } + + public virtual Geometry GeometryB + { + get => geometryB; + set => geometryB = value; + } + + public virtual string Operation + { + get => operation; + set => operation = value; + } + + public virtual string RelatePattern + { + get => relatePattern; + set => relatePattern = value; + } + + public virtual Geometry GeometryResult + { + get => geometryResult; + set => geometryResult = value; + } + + public virtual bool BooleanResult + { + get => booleanResult; + set => booleanResult = value; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.hbm.xml b/Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.hbm.xml new file mode 100644 index 0000000..2ddd630 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/NtsTestCases/Model/NtsTestCase.hbm.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + 0 + GEOMETRY + + + + + 0 + GEOMETRY + + + + + + + 0 + GEOMETRY + + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.cs b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.cs new file mode 100644 index 0000000..5ae752a --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.cs @@ -0,0 +1,49 @@ +using NetTopologySuite.Geometries; +using System; + +namespace Tests.NHibernate.Spatial.RandomGeometries.Model +{ + [Serializable] + public class LineStringEntity + { + private long id; + + private string name; + + private Geometry geometry; + + public LineStringEntity() + { } + + public LineStringEntity(string name, Geometry geometry) + { + Name = name; + Geometry = geometry; + } + + public LineStringEntity(long id, string name, Geometry geometry) + { + Id = id; + Name = name; + Geometry = geometry; + } + + public virtual long Id + { + get => id; + set => id = value; + } + + public virtual string Name + { + get => name; + set => name = value; + } + + public virtual Geometry Geometry + { + get => geometry; + set => geometry = value; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.hbm.xml b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.hbm.xml new file mode 100644 index 0000000..9f7af91 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/LineStringEntity.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + LINESTRING + 0 + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.cs b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.cs new file mode 100644 index 0000000..69d9958 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.cs @@ -0,0 +1,49 @@ +using NetTopologySuite.Geometries; +using System; + +namespace Tests.NHibernate.Spatial.RandomGeometries.Model +{ + [Serializable] + public class MultiLineStringEntity + { + private long id; + + private string name; + + private Geometry geometry; + + public MultiLineStringEntity() + { } + + public MultiLineStringEntity(string name, Geometry geometry) + { + Name = name; + Geometry = geometry; + } + + public MultiLineStringEntity(long id, string name, Geometry geometry) + { + Id = id; + Name = name; + Geometry = geometry; + } + + public virtual long Id + { + get => id; + set => id = value; + } + + public virtual string Name + { + get => name; + set => name = value; + } + + public virtual Geometry Geometry + { + get => geometry; + set => geometry = value; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.hbm.xml b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.hbm.xml new file mode 100644 index 0000000..2adf5c3 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiLineStringEntity.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + MULTILINESTRING + 0 + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.cs b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.cs new file mode 100644 index 0000000..1af8d4a --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.cs @@ -0,0 +1,49 @@ +using NetTopologySuite.Geometries; +using System; + +namespace Tests.NHibernate.Spatial.RandomGeometries.Model +{ + [Serializable] + public class MultiPointEntity + { + private long id; + + private string name; + + private Geometry geometry; + + public MultiPointEntity() + { } + + public MultiPointEntity(string name, Geometry geometry) + { + Name = name; + Geometry = geometry; + } + + public MultiPointEntity(long id, string name, Geometry geometry) + { + Id = id; + Name = name; + Geometry = geometry; + } + + public virtual long Id + { + get => id; + set => id = value; + } + + public virtual string Name + { + get => name; + set => name = value; + } + + public virtual Geometry Geometry + { + get => geometry; + set => geometry = value; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.hbm.xml b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.hbm.xml new file mode 100644 index 0000000..7dba86b --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPointEntity.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + MULTIPOINT + 0 + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.cs b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.cs new file mode 100644 index 0000000..438291f --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.cs @@ -0,0 +1,49 @@ +using NetTopologySuite.Geometries; +using System; + +namespace Tests.NHibernate.Spatial.RandomGeometries.Model +{ + [Serializable] + public class MultiPolygonEntity + { + private long id; + + private string name; + + private Geometry geometry; + + public MultiPolygonEntity() + { } + + public MultiPolygonEntity(string name, Geometry geometry) + { + Name = name; + Geometry = geometry; + } + + public MultiPolygonEntity(long id, string name, Geometry geometry) + { + Id = id; + Name = name; + Geometry = geometry; + } + + public virtual long Id + { + get => id; + set => id = value; + } + + public virtual string Name + { + get => name; + set => name = value; + } + + public virtual Geometry Geometry + { + get => geometry; + set => geometry = value; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.hbm.xml b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.hbm.xml new file mode 100644 index 0000000..e0b41af --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/MultiPolygonEntity.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + MULTIPOLYGON + 0 + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.cs b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.cs new file mode 100644 index 0000000..8d24807 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.cs @@ -0,0 +1,49 @@ +using NetTopologySuite.Geometries; +using System; + +namespace Tests.NHibernate.Spatial.RandomGeometries.Model +{ + [Serializable] + public class PointEntity + { + private long id; + + private string name; + + private Geometry geometry; + + public PointEntity() + { } + + public PointEntity(string name, Geometry geometry) + { + Name = name; + Geometry = geometry; + } + + public PointEntity(long id, string name, Geometry geometry) + { + Id = id; + Name = name; + Geometry = geometry; + } + + public virtual long Id + { + get => id; + set => id = value; + } + + public virtual string Name + { + get => name; + set => name = value; + } + + public virtual Geometry Geometry + { + get => geometry; + set => geometry = value; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.hbm.xml b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.hbm.xml new file mode 100644 index 0000000..677c107 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PointEntity.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + POINT + 0 + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.cs b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.cs new file mode 100644 index 0000000..cfb21ca --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.cs @@ -0,0 +1,49 @@ +using NetTopologySuite.Geometries; +using System; + +namespace Tests.NHibernate.Spatial.RandomGeometries.Model +{ + [Serializable] + public class PolygonEntity + { + private long id; + + private string name; + + private Geometry geometry; + + public PolygonEntity() + { } + + public PolygonEntity(string name, Geometry geometry) + { + Name = name; + Geometry = geometry; + } + + public PolygonEntity(long id, string name, Geometry geometry) + { + Id = id; + Name = name; + Geometry = geometry; + } + + public virtual long Id + { + get => id; + set => id = value; + } + + public virtual string Name + { + get => name; + set => name = value; + } + + public virtual Geometry Geometry + { + get => geometry; + set => geometry = value; + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.hbm.xml b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.hbm.xml new file mode 100644 index 0000000..2099683 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/RandomGeometries/Model/PolygonEntity.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + POLYGON + 0 + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/TestConfiguration.cs b/Tests.NHibernate.Spatial.MySQL80/TestConfiguration.cs new file mode 100644 index 0000000..ef07485 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/TestConfiguration.cs @@ -0,0 +1,34 @@ +using Microsoft.Extensions.Configuration; +using NHibernate.Bytecode; +using NHibernate.Cfg; +using NHibernate.Driver; +using NHibernate.Spatial.Dialect; +using System.Collections.Generic; + +namespace Tests.NHibernate.Spatial +{ + internal static class TestConfiguration + { + private static readonly IConfigurationRoot _configurationRoot; + + static TestConfiguration() + { + _configurationRoot = new ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .Build(); + } + + public static void Configure(Configuration configuration) + { + IDictionary properties = new Dictionary + { + [Environment.ProxyFactoryFactoryClass] = typeof(StaticProxyFactoryFactory).AssemblyQualifiedName, + [Environment.Dialect] = typeof(MySQL80SpatialDialect).AssemblyQualifiedName, + [Environment.ConnectionProvider] = typeof(DebugConnectionProvider).AssemblyQualifiedName, + [Environment.ConnectionDriver] = typeof(MySqlDataDriver).AssemblyQualifiedName, + [Environment.ConnectionString] = _configurationRoot.GetConnectionString("MySQL80") + }; + configuration.SetProperties(properties); + } + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/Tests.NHibernate.Spatial.MySQL80.csproj b/Tests.NHibernate.Spatial.MySQL80/Tests.NHibernate.Spatial.MySQL80.csproj new file mode 100644 index 0000000..f17a25c --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/Tests.NHibernate.Spatial.MySQL80.csproj @@ -0,0 +1,39 @@ + + + + net6.0 + + false + + Tests.NHibernate.Spatial + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + diff --git a/Tests.NHibernate.Spatial.MySQL80/appsettings.json b/Tests.NHibernate.Spatial.MySQL80/appsettings.json new file mode 100644 index 0000000..bf1b795 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/appsettings.json @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "MySQL80": "Server=localhost;Port=13307;Database=nhsp_test;User Id=nhsp_test;Password=nhsp_test;" + } +} diff --git a/Tests.NHibernate.Spatial.MySQL80/initdb/nhsp_test.sql b/Tests.NHibernate.Spatial.MySQL80/initdb/nhsp_test.sql new file mode 100644 index 0000000..e583fc8 --- /dev/null +++ b/Tests.NHibernate.Spatial.MySQL80/initdb/nhsp_test.sql @@ -0,0 +1,14 @@ +/* NHibernate.Spatial MySQL 8.0 Test Database Creation Script */ + +-- Run this script as superuser using mysql, i.e.: +-- mysql -P 3307 -u root -p"password" < path-to-this-file.sql + +CREATE USER 'nhsp_test'@'%' IDENTIFIED BY 'nhsp_test'; + +CREATE DATABASE IF NOT EXISTS `nhsp_test` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; + +GRANT ALL PRIVILEGES ON `nhsp_test`.* TO 'nhsp_test'@'%'; + +-- Required to be able to insert/delete custom SRS; see: +-- https://dev.mysql.com/doc/refman/8.0/en/create-spatial-reference-system.html +GRANT SUPER ON *.* TO 'nhsp_test'@'%'; diff --git a/Tests.NHibernate.Spatial/OgcSfSql11Compliance/ConformanceItemsFixture.cs b/Tests.NHibernate.Spatial/OgcSfSql11Compliance/ConformanceItemsFixture.cs index bcb9aad..27db22a 100644 --- a/Tests.NHibernate.Spatial/OgcSfSql11Compliance/ConformanceItemsFixture.cs +++ b/Tests.NHibernate.Spatial/OgcSfSql11Compliance/ConformanceItemsFixture.cs @@ -24,7 +24,7 @@ public abstract class ConformanceItemsFixture : AbstractFixture // Tolerance for floating point precision protected const double Tolerance = 0.000000000001; - private const string SpatialReferenceSystemWKT = + protected virtual string SpatialReferenceSystemWKT => @"PROJCS[""UTM_ZONE_14N"", GEOGCS[""World Geodetic System 72"", DATUM[""WGS_72"", SPHEROID[""NWL_10D"", 6378135, 298.26]], PRIMEM[""Greenwich"", 0], UNIT[""Meter"", 1.0]], @@ -300,7 +300,7 @@ from g in session.Query() /// /// [Test] - public void ConformanceItemT03Hql() + public virtual void ConformanceItemT03Hql() { if (!Metadata.SupportsSpatialMetadata(session, MetadataClass.GeometryColumn)) { @@ -318,7 +318,7 @@ from GeometryColumn g } [Test] - public void ConformanceItemT03Linq() + public virtual void ConformanceItemT03Linq() { if (!Metadata.SupportsSpatialMetadata(session, MetadataClass.GeometryColumn)) { diff --git a/Tests.NHibernate.Spatial/RandomGeometries/DataGenerator.cs b/Tests.NHibernate.Spatial/RandomGeometries/DataGenerator.cs index cd5b108..f183fc4 100644 --- a/Tests.NHibernate.Spatial/RandomGeometries/DataGenerator.cs +++ b/Tests.NHibernate.Spatial/RandomGeometries/DataGenerator.cs @@ -5,7 +5,7 @@ namespace Tests.NHibernate.Spatial.RandomGeometries { - internal static class DataGenerator + public static class DataGenerator { private const int GeneratedRowsPerEntityCount = 11; private const int MinCoordValue = 0; @@ -19,14 +19,14 @@ private interface IGeometryCreator Geometry Create(); } - public static void Generate(ISessionFactory factory) + public static void Generate(ISessionFactory factory, int srid) { - GenerateData(factory, typeof(LineStringEntity), new LineStringCreator()); - GenerateData(factory, typeof(MultiLineStringEntity), new MultiLineStringCreator()); - GenerateData(factory, typeof(PolygonEntity), new PolygonCreator()); + GenerateData(factory, typeof(LineStringEntity), new LineStringCreator(), srid); + GenerateData(factory, typeof(MultiLineStringEntity), new MultiLineStringCreator(), srid); + GenerateData(factory, typeof(PolygonEntity), new PolygonCreator(), srid); } - private static void GenerateData(ISessionFactory factory, Type entityClass, IGeometryCreator creator) + private static void GenerateData(ISessionFactory factory, Type entityClass, IGeometryCreator creator, int srid) { using (var session = factory.OpenSession()) { @@ -37,7 +37,7 @@ private static void GenerateData(ISessionFactory factory, Type entityClass, IGeo for (int i = 0; i < GeneratedRowsPerEntityCount; i++) { var geom = creator.Create(); - geom.SRID = 4326; + geom.SRID = srid; object entity = Activator.CreateInstance(entityClass, i, "feature " + i, geom); session.Save(entity); } diff --git a/Tests.NHibernate.Spatial/RandomGeometries/SpatialQueriesFixture.cs b/Tests.NHibernate.Spatial/RandomGeometries/SpatialQueriesFixture.cs index df3536e..c2f1a1c 100644 --- a/Tests.NHibernate.Spatial/RandomGeometries/SpatialQueriesFixture.cs +++ b/Tests.NHibernate.Spatial/RandomGeometries/SpatialQueriesFixture.cs @@ -13,10 +13,10 @@ namespace Tests.NHibernate.Spatial.RandomGeometries /// public abstract class SpatialQueriesFixture : AbstractFixture { - private const string FilterString = "POLYGON((0.0 0.0, 25000.0 0.0, 25000.0 25000.0, 0.0 25000.0, 0.0 0.0))"; + protected const string FilterString = "POLYGON((0.0 0.0, 25000.0 0.0, 25000.0 25000.0, 0.0 25000.0, 0.0 0.0))"; protected ISession Session; - private Geometry _filter; + protected Geometry Filter; protected override Type[] Mappings { @@ -40,7 +40,7 @@ protected override Type[] Mappings public void LineStringFiltering() { var results = Session.CreateCriteria(typeof(LineStringEntity)) - .Add(SpatialRestrictions.Filter("Geometry", _filter)) + .Add(SpatialRestrictions.Filter("Geometry", Filter)) .List(); long count; @@ -57,7 +57,7 @@ public void LineStringFiltering() public void PolygonFiltering() { var results = Session.CreateCriteria(typeof(PolygonEntity)) - .Add(SpatialRestrictions.Filter("Geometry", _filter)) + .Add(SpatialRestrictions.Filter("Geometry", Filter)) .List(); long count; @@ -74,7 +74,7 @@ public void PolygonFiltering() public void MultiLineStringFiltering() { var results = Session.CreateCriteria(typeof(MultiLineStringEntity)) - .Add(SpatialRestrictions.Filter("Geometry", _filter)) + .Add(SpatialRestrictions.Filter("Geometry", Filter)) .List(); long count; @@ -131,13 +131,13 @@ public void HqlOverlapsLineString() var results = Session .CreateQuery( "select NHSP.Overlaps(?,l.Geometry) from LineStringEntity as l where l.Geometry is not null") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .List(); long countOverlapping = 0; - foreach (bool isOverlapped in results) + foreach (bool? isOverlapped in results) { - if (isOverlapped) + if (isOverlapped.HasValue && isOverlapped.Value) { countOverlapping++; } @@ -159,7 +159,7 @@ public virtual void HqlRelateLineString() long count = Session .CreateQuery( "select count(*) from LineStringEntity l where l.Geometry is not null and NHSP.Relate(l.Geometry, ?, 'TT*******') = true") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .UniqueResult(); Assert.Greater((int) count, 0); @@ -171,7 +171,7 @@ public void HqlIntersectsLineString() var results = Session .CreateQuery( "select NHSP.Intersects(?,l.Geometry) from LineStringEntity as l where l.Geometry is not null") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .List(); long intersects = 0; @@ -185,7 +185,7 @@ public void HqlIntersectsLineString() long altIntersects = Session .CreateQuery("select count(*) from LineStringEntity as l where NHSP.Intersects(l.Geometry, ?) = true") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .UniqueResult(); Assert.AreEqual(intersects, altIntersects); @@ -201,14 +201,14 @@ public void HqlIntersectsLineString() results = Session .CreateQuery("from LineStringEntity as l where NHSP.Intersects(?,l.Geometry) = true") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .List(); Assert.AreEqual(count, results.Count); } [Test] - public void HqlSRID() + public virtual void HqlSRID() { var results = Session .CreateQuery("select NHSP.SRID(l.Geometry) from LineStringEntity as l where l.Geometry is not null") @@ -309,7 +309,7 @@ public virtual void HqlBoundary() } [Test] - public void HqlAsBoundary() + public void HqlAsBinary() { var results = Session .CreateQuery( @@ -337,14 +337,14 @@ public void HqlDistance() select NHSP.Distance(l.Geometry, ?), l.Geometry from LineStringEntity as l where l.Geometry is not null") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .SetMaxResults(100) .List(); foreach (object[] item in results) { double distance = (double) item[0]; var geom = (Geometry) item[1]; - Assert.AreEqual(geom.Distance(_filter), distance, 0.003); + Assert.AreEqual(geom.Distance(Filter), distance, 0.003); } } @@ -361,7 +361,7 @@ from LineStringEntity as l where l.Geometry is not null and NHSP.Distance(l.Geometry, :filter) > :minDistance order by NHSP.Distance(l.Geometry, :filter)") - .SetParameter("filter", _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter("filter", Filter, SpatialDialect.GeometryTypeOf(Session)) .SetParameter("minDistance", minDistance) .SetMaxResults(100) .List(); @@ -372,7 +372,7 @@ order by NHSP.Distance(l.Geometry, :filter)") double distance = (double) item[0]; Assert.Greater(distance, minDistance); var geom = (Geometry) item[1]; - Assert.AreEqual(geom.Distance(_filter), distance, 0.003); + Assert.AreEqual(geom.Distance(Filter), distance, 0.003); } } @@ -441,7 +441,7 @@ public void HqlDifference() var results = Session .CreateQuery( "select e.Geometry, NHSP.Difference(e.Geometry, ?) from PolygonEntity as e where e.Geometry is not null") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .SetMaxResults(100) .List(); @@ -459,7 +459,7 @@ public void HqlDifference() } diff.Normalize(); - var ntsDiff = geom.Difference(_filter); + var ntsDiff = geom.Difference(Filter); ntsDiff.Normalize(); if (ntsDiff.EqualsExact(diff, 0.5)) @@ -476,7 +476,7 @@ public void HqlIntersection() var results = Session .CreateQuery( "select e.Geometry, NHSP.Intersection(e.Geometry, ?) from PolygonEntity as e where e.Geometry is not null") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .SetMaxResults(100) .List(); @@ -494,7 +494,7 @@ public void HqlIntersection() } intersect.Normalize(); - var ntsIntersect = geom.Intersection(_filter); + var ntsIntersect = geom.Intersection(Filter); ntsIntersect.Normalize(); if (ntsIntersect.EqualsExact(intersect, 0.5)) @@ -511,7 +511,7 @@ public void HqlSymDifference() var results = Session .CreateQuery( "select e.Geometry, NHSP.SymDifference(e.Geometry, ?) from PolygonEntity as e where e.Geometry is not null") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .SetMaxResults(100) .List(); @@ -529,7 +529,7 @@ public void HqlSymDifference() } symDiff.Normalize(); - var ntsSymDiff = geom.SymmetricDifference(_filter); + var ntsSymDiff = geom.SymmetricDifference(Filter); ntsSymDiff.Normalize(); if (ntsSymDiff.EqualsExact(symDiff, 0.5)) @@ -546,7 +546,7 @@ public void HqlUnion() var results = Session .CreateQuery( "select e.Geometry, NHSP.Union(e.Geometry, ?) from PolygonEntity as e where e.Geometry is not null") - .SetParameter(0, _filter, SpatialDialect.GeometryTypeOf(Session)) + .SetParameter(0, Filter, SpatialDialect.GeometryTypeOf(Session)) .SetMaxResults(100) .List(); @@ -564,7 +564,7 @@ public void HqlUnion() } union.Normalize(); - var ntsUnion = geom.Union(_filter); + var ntsUnion = geom.Union(Filter); ntsUnion.Normalize(); if (ntsUnion.EqualsExact(union, 0.5)) @@ -577,10 +577,11 @@ public void HqlUnion() protected override void OnTestFixtureSetUp() { - DataGenerator.Generate(sessions); + const int srid = 4326; + DataGenerator.Generate(sessions, srid); - _filter = Wkt.Read(FilterString); - _filter.SRID = 4326; + Filter = Wkt.Read(FilterString); + Filter.SRID = srid; } protected override void OnTestFixtureTearDown() diff --git a/docker-compose.yml b/docker-compose.yml index 0a1681c..c107526 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,6 +36,15 @@ services: volumes: - ./Tests.NHibernate.Spatial.MySQL57/initdb:/docker-entrypoint-initdb.d + mysql80: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: # See .env file + ports: + - 13307:3306 + volumes: + - ./Tests.NHibernate.Spatial.MySQL80/initdb:/docker-entrypoint-initdb.d + postgis20: image: postgis/postgis:12-2.5 environment: