Index: Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj =================================================================== diff -u -r32535803492f107f7405399b93166d26446b77b7 -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 --- Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj (.../Ringtoets.Common.IO.csproj) (revision 32535803492f107f7405399b93166d26446b77b7) +++ Ringtoets/Common/src/Ringtoets.Common.IO/Ringtoets.Common.IO.csproj (.../Ringtoets.Common.IO.csproj) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -127,6 +127,7 @@ + Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/ISoilProfile.cs =================================================================== diff -u -r58d98ab4a0a75497b2752eff1a931f6f7ee3fa8a -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/ISoilProfile.cs (.../ISoilProfile.cs) (revision 58d98ab4a0a75497b2752eff1a931f6f7ee3fa8a) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/ISoilProfile.cs (.../ISoilProfile.cs) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -22,7 +22,7 @@ namespace Ringtoets.Common.IO.SoilProfile { /// - /// This class represents a soil profile. + /// Interface for the different types of soil profiles. /// public interface ISoilProfile { Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/Schema/SegmentTableDefinitions.cs =================================================================== diff -u -r6379e5b1f8fd510f54137ceed602bd2900cdf235 -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/Schema/SegmentTableDefinitions.cs (.../SegmentTableDefinitions.cs) (revision 6379e5b1f8fd510f54137ceed602bd2900cdf235) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/Schema/SegmentTableDefinitions.cs (.../SegmentTableDefinitions.cs) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -32,6 +32,11 @@ public const string TableName = "Segment"; /// + /// Gets the name of the segment id column. + /// + public const string SegmentId = "SE_ID"; + + /// /// Gets the name of the segment name column. /// public const string SegmentName = "SE_Name"; Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SegmentPointReader.cs =================================================================== diff -u --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SegmentPointReader.cs (revision 0) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SegmentPointReader.cs (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -0,0 +1,108 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SQLite; +using Core.Common.Base.Geometry; +using Core.Common.Base.IO; +using Core.Common.IO.Readers; +using Core.Common.Utils.Builders; +using Ringtoets.Common.IO.Properties; +using Ringtoets.Common.IO.SoilProfile.Schema; + +namespace Ringtoets.Common.IO.SoilProfile +{ + /// + /// This class reads a DSoil database file and reads segment points from this database. + /// + public class SegmentPointReader : SqLiteDatabaseReaderBase + { + private IDataReader dataReader; + + public SegmentPointReader(string databaseFilePath) : base(databaseFilePath) {} + + public void Initialize() + { + InitializeReader(); + } + + public IEnumerable ReadSegmentPoints(long stochasticSoilModelId) + { + while (HasNext && ReadStochasticSoilModelSegmentId() == stochasticSoilModelId) + { + yield return ReadSegmentPoint(); + MoveNext(); + } + } + + protected override void Dispose(bool disposing) + { + if (dataReader != null) + { + dataReader.Close(); + dataReader.Dispose(); + dataReader = null; + } + base.Dispose(disposing); + } + + private bool HasNext { get; set; } + + private long ReadStochasticSoilModelSegmentId() + { + return Convert.ToInt64(dataReader[StochasticSoilModelTableDefinitions.StochasticSoilModelId]); + } + + private Point2D ReadSegmentPoint() + { + double coordinateX = Convert.ToDouble(dataReader[SegmentPointsTableDefinitions.CoordinateX]); + double coordinateY = Convert.ToDouble(dataReader[SegmentPointsTableDefinitions.CoordinateY]); + return new Point2D(coordinateX, coordinateY); + } + + private void InitializeReader() + { + CreateDataReader(); + MoveNext(); + } + + private void CreateDataReader() + { + string stochasticSoilModelSegmentsQuery = SoilDatabaseQueryBuilder.GetSegmentPointsQuery(); + try + { + dataReader = CreateDataReader(stochasticSoilModelSegmentsQuery); + } + catch (SQLiteException exception) + { + string message = new FileReaderErrorMessageBuilder(Path).Build(Resources.StochasticSoilModelDatabaseReader_Failed_to_read_database); + throw new CriticalFileReadException(message, exception); + } + } + + private void MoveNext() + { + HasNext = MoveNext(dataReader); + } + } +} \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilDatabaseQueryBuilder.cs =================================================================== diff -u -r0ec64f4150d76a9530b3bed3f1af18334b5bf673 -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilDatabaseQueryBuilder.cs (.../SoilDatabaseQueryBuilder.cs) (revision 0ec64f4150d76a9530b3bed3f1af18334b5bf673) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilDatabaseQueryBuilder.cs (.../SoilDatabaseQueryBuilder.cs) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -104,18 +104,39 @@ } /// - /// Returns the SQL query to execute to fetch all stochastic soil profiles - /// from the DSoil-Model database. + /// Returns the SQL query to execute to fetch stochastic soil models + /// per failure mechanism from the DSoil-Model database. /// /// The SQL query to execute. - public static string GetAllStochasticSoilProfileQuery() + public static string GetStochasticSoilModelPerMechanismQuery() { - return string.Format("SELECT {1}, {2}, {3}, {4} FROM {0} ORDER BY {1};", - StochasticSoilProfileTableDefinitions.TableName, - StochasticSoilProfileTableDefinitions.StochasticSoilModelId, - StochasticSoilProfileTableDefinitions.Probability, - StochasticSoilProfileTableDefinitions.SoilProfile1DId, - StochasticSoilProfileTableDefinitions.SoilProfile2DId); + return $"SELECT M.{MechanismTableDefinitions.MechanismName}, " + + $"SSM.{StochasticSoilModelTableDefinitions.StochasticSoilModelId}, " + + $"SSM.{StochasticSoilModelTableDefinitions.StochasticSoilModelName}, " + + $"SSP.{StochasticSoilProfileTableDefinitions.Probability}, " + + $"SSP.{StochasticSoilProfileTableDefinitions.SoilProfile1DId}, " + + $"SSP.{StochasticSoilProfileTableDefinitions.SoilProfile2DId} " + + $"FROM {MechanismTableDefinitions.TableName} M " + + $"INNER JOIN {SegmentTableDefinitions.TableName} S USING({MechanismTableDefinitions.MechanismId}) " + + $"INNER JOIN {StochasticSoilModelTableDefinitions.TableName} SSM USING({StochasticSoilModelTableDefinitions.StochasticSoilModelId}) " + + $"INNER JOIN {StochasticSoilProfileTableDefinitions.TableName} SSP USING({StochasticSoilModelTableDefinitions.StochasticSoilModelId}) " + + $"ORDER BY M.{MechanismTableDefinitions.MechanismName}, SSM.{StochasticSoilModelTableDefinitions.StochasticSoilModelId};"; } + + /// + /// Returns the SQL query to execute to fetch segments and segment points + /// per stochastic soil model from the DSoil-Model database. + /// + /// The SQL query to execute. + public static string GetSegmentPointsQuery() + { + return $"SELECT SSM.{StochasticSoilModelTableDefinitions.StochasticSoilModelId}, " + + $"SP.{SegmentPointsTableDefinitions.CoordinateX}, " + + $"SP.{SegmentPointsTableDefinitions.CoordinateY} " + + $"FROM {SegmentTableDefinitions.TableName} S " + + $"INNER JOIN {StochasticSoilModelTableDefinitions.TableName} SSM USING({StochasticSoilModelTableDefinitions.StochasticSoilModelId}) " + + $"INNER JOIN {SegmentPointsTableDefinitions.TableName} SP USING({SegmentTableDefinitions.SegmentId}) " + + $"ORDER BY SSM.{StochasticSoilModelTableDefinitions.StochasticSoilModelId};"; + } } } \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs =================================================================== diff -u -r32535803492f107f7405399b93166d26446b77b7 -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs (.../SoilProfile1DReader.cs) (revision 32535803492f107f7405399b93166d26446b77b7) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/SoilProfile1DReader.cs (.../SoilProfile1DReader.cs) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -72,6 +72,7 @@ /// /// The next from the database, or null /// if no more soil profile can be read. + /// Thrown when reading properties of the profile failed. /// Thrown when the database returned incorrect /// values for required properties. public SoilProfile1D ReadSoilProfile() Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj =================================================================== diff -u -r32535803492f107f7405399b93166d26446b77b7 -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj (.../Ringtoets.Common.IO.Test.csproj) (revision 32535803492f107f7405399b93166d26446b77b7) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/Ringtoets.Common.IO.Test.csproj (.../Ringtoets.Common.IO.Test.csproj) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -110,6 +110,7 @@ + Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SegmentPointReaderTest.cs =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SegmentPointReaderTest.cs (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SegmentPointReaderTest.cs (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -0,0 +1,130 @@ +// Copyright (C) Stichting Deltares 2017. All rights reserved. +// +// This file is part of Ringtoets. +// +// Ringtoets is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// All names, logos, and references to "Deltares" are registered trademarks of +// Stichting Deltares and remain full property of Stichting Deltares at all times. +// All rights reserved. + +using System.IO; +using System.Linq; +using Core.Common.Base.Geometry; +using Core.Common.Base.IO; +using Core.Common.IO.Readers; +using Core.Common.TestUtil; +using Core.Common.Utils.Builders; +using NUnit.Framework; +using Ringtoets.Common.IO.SoilProfile; + +namespace Ringtoets.Common.IO.Test.SoilProfile +{ + [TestFixture] + public class SegmentPointReaderTest + { + private readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Ringtoets.Common.IO, nameof(SegmentPointReader)); + + [Test] + public void Constructor_NonExistingPath_ThrowsCriticalFileReadException() + { + // Setup + string testFile = Path.Combine(testDataPath, "does not exist"); + + // Call + TestDelegate test = () => + { + using (new SegmentPointReader(testFile)) {} + }; + + // Assert + var exception = Assert.Throws(test); + string expectedMessage = new FileReaderErrorMessageBuilder(testFile).Build("Het bestand bestaat niet."); + Assert.AreEqual(expectedMessage, exception.Message); + } + + [Test] + [TestCaseSource(typeof(InvalidPathHelper), nameof(InvalidPathHelper.InvalidPaths))] + public void Constructor_FileNullOrEmpty_ThrowsCriticalFileReadException(string fileName) + { + // Call + TestDelegate test = () => + { + using (new SegmentPointReader(fileName)) {} + }; + + // Assert + Assert.Throws(test); + } + + [Test] + public void Constructor_PathToExistingFile_ExpectedValues() + { + // Setup + string dbFile = Path.Combine(testDataPath, "emptySchema.soil"); + + // Call + using (var reader = new SegmentPointReader(dbFile)) + { + // Assert + Assert.AreEqual(dbFile, reader.Path); + Assert.IsInstanceOf(reader); + } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); + } + + [Test] + public void Initialize_IncorrectFormatFile_ThrowsCriticalFileReadException() + { + // Setup + string dbFile = Path.Combine(testDataPath, "text.txt"); + + using (var reader = new SegmentPointReader(dbFile)) + { + // Call + TestDelegate test = () => reader.Initialize(); + + // Assert + var exception = Assert.Throws(test); + + string expectedMessage = new FileReaderErrorMessageBuilder(dbFile).Build( + "Kon geen stochastische ondergrondmodellen verkrijgen uit de database."); + Assert.AreEqual(expectedMessage, exception.Message); + } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); + } + + [Test] + public void ReadStochasticSoilModel_EmptyDatabase_ReturnsFalse() + { + // Setup + string dbFile = Path.Combine(testDataPath, "emptySchema.soil"); + + using (var reader = new SegmentPointReader(dbFile)) + { + reader.Initialize(); + + // Call + Point2D[] segmentPoints = reader.ReadSegmentPoints(1).ToArray(); + + // Assert + CollectionAssert.IsEmpty(segmentPoints); + } + + Assert.IsTrue(TestHelper.CanOpenFileForWrite(dbFile)); + } + } +} \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilDatabaseQueryBuilderTest.cs =================================================================== diff -u -r0ec64f4150d76a9530b3bed3f1af18334b5bf673 -r1d91b8411e6db990c17fade0ad12aa8ac0e54865 --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilDatabaseQueryBuilderTest.cs (.../SoilDatabaseQueryBuilderTest.cs) (revision 0ec64f4150d76a9530b3bed3f1af18334b5bf673) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/SoilDatabaseQueryBuilderTest.cs (.../SoilDatabaseQueryBuilderTest.cs) (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -34,10 +34,11 @@ string query = SoilDatabaseQueryBuilder.GetCheckVersionQuery(); // Assert - const string expectedQuery = "SELECT Value " + - "FROM _MetaData " + - "WHERE Key = 'VERSION' " + - "AND Value = @Value;"; + const string expectedQuery = + "SELECT Value " + + "FROM _MetaData " + + "WHERE Key = 'VERSION' " + + "AND Value = @Value;"; Assert.AreEqual(expectedQuery, query); } @@ -62,9 +63,10 @@ string query = SoilDatabaseQueryBuilder.GetStochasticSoilProfileProbabilitiesValidQuery(); // Assert - const string expectedQuery = "SELECT COUNT(Probability) == 0 AS AllProbabilitiesValid " + - "FROM StochasticSoilProfile " + - "WHERE Probability NOT BETWEEN 0 AND 1 OR Probability ISNULL;"; + const string expectedQuery = + "SELECT COUNT(Probability) == 0 AS AllProbabilitiesValid " + + "FROM StochasticSoilProfile " + + "WHERE Probability NOT BETWEEN 0 AND 1 OR Probability ISNULL;"; Assert.AreEqual(expectedQuery, query); } @@ -75,26 +77,47 @@ string query = SoilDatabaseQueryBuilder.GetStochasticSoilModelOfMechanismQuery(); // Assert - const string expectedQuery = @"SELECT M.ME_Name, SP.XWorld, SP.YWorld, S.SE_Name, SSM.SSM_Name, SSM.SSM_ID " + - "FROM Mechanism M " + - "INNER JOIN Segment S USING(ME_ID) " + - "INNER JOIN StochasticSoilModel SSM USING(SSM_ID) " + - "INNER JOIN SegmentPoints SP USING(SE_ID) " + - "ORDER BY M.ME_Name, SSM.SSM_ID;"; + const string expectedQuery = + "SELECT M.ME_Name, SP.XWorld, SP.YWorld, S.SE_Name, SSM.SSM_Name, SSM.SSM_ID " + + "FROM Mechanism M " + + "INNER JOIN Segment S USING(ME_ID) " + + "INNER JOIN StochasticSoilModel SSM USING(SSM_ID) " + + "INNER JOIN SegmentPoints SP USING(SE_ID) " + + "ORDER BY M.ME_Name, SSM.SSM_ID;"; Assert.AreEqual(expectedQuery, query); } [Test] - public void GetAllStochasticSoilProfileQuery_ReturnsExpectedValues() + public void GetStochasticSoilModelPerMechanismQuery_ReturnsExpectedValues() { // Call - string query = SoilDatabaseQueryBuilder.GetAllStochasticSoilProfileQuery(); + string query = SoilDatabaseQueryBuilder.GetStochasticSoilModelPerMechanismQuery(); // Assert - const string expectedQuery = "SELECT SSM_ID, Probability, SP1D_ID, SP2D_ID " + - "FROM StochasticSoilProfile " + - "ORDER BY SSM_ID;"; + const string expectedQuery = + "SELECT M.ME_Name, SSM.SSM_ID, SSM.SSM_Name, SSP.Probability, SSP.SP1D_ID, SSP.SP2D_ID " + + "FROM Mechanism M " + + "INNER JOIN Segment S USING(ME_ID) " + + "INNER JOIN StochasticSoilModel SSM USING(SSM_ID) " + + "INNER JOIN StochasticSoilProfile SSP USING(SSM_ID) " + + "ORDER BY M.ME_Name, SSM.SSM_ID;"; Assert.AreEqual(expectedQuery, query); } + + [Test] + public void GetSegmentPointsQuery_ReturnsExpectedValues() + { + // Call + string query = SoilDatabaseQueryBuilder.GetSegmentPointsQuery(); + + // Assert + const string expectedQuery = + "SELECT SSM.SSM_ID, SP.XWorld, SP.YWorld " + + "FROM Segment S " + + "INNER JOIN StochasticSoilModel SSM USING(SSM_ID) " + + "INNER JOIN SegmentPoints SP USING(SE_ID) " + + "ORDER BY SSM.SSM_ID;"; + Assert.AreEqual(expectedQuery, query); + } } } \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SegmentPointReader/emptySchema.soil =================================================================== diff -u Binary files differ Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SegmentPointReader/text.txt =================================================================== diff -u --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SegmentPointReader/text.txt (revision 0) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/test-data/SegmentPointReader/text.txt (revision 1d91b8411e6db990c17fade0ad12aa8ac0e54865) @@ -0,0 +1 @@ +SomeText \ No newline at end of file