// Copyright (C) Stichting Deltares 2016. 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.Data; using System.Data.SQLite; using Core.Common.IO.Exceptions; using Core.Common.IO.Readers; using Core.Common.Utils.Builders; using Ringtoets.HydraRing.Data; using Ringtoets.HydraRing.IO.Properties; namespace Ringtoets.HydraRing.IO { /// /// This class reads a SqLite database file and constructs instances from this database. /// public class HydraulicBoundarySqLiteDatabaseReader : SqLiteDatabaseReaderBase, IRowBasedDatabaseReader { private SQLiteDataReader dataReader; /// /// Creates a new instance of , which will use the /// as its source. /// /// The path of the database file to open. /// Thrown when: /// /// The contains invalid characters. /// No file could be found at . /// Preparing the queries to read from the database failed. /// /// public HydraulicBoundarySqLiteDatabaseReader(string databaseFilePath) : base(databaseFilePath) { InitializeReader(); } /// /// Gets the total number of locations that can be read from the database. /// public int Count { get; private set; } /// /// Gets the version from the database. /// public string Version { get; private set; } /// /// Gets the value true if locations can be read using the . /// false otherwise. /// public bool HasNext { get; private set; } /// /// Reads the next location from the database. /// /// New instance of , based on the data read from the database or null if no data is available. /// Thrown when the database returned incorrect values for required properties. public HydraulicBoundaryLocation ReadLocation() { if (!HasNext) { return null; } try { return ReadHydraulicBoundaryLocation(); } catch (InvalidCastException e) { var message = new FileReaderErrorMessageBuilder(Path).Build(Resources.HydraulicBoundaryDatabaseReader_Critical_Unexpected_value_on_column); throw new CriticalFileReadException(message, e); } } /// /// Disposes the reader. /// public override void Dispose() { if (dataReader != null) { dataReader.Dispose(); } base.Dispose(); } /// /// Moves the reader to the next record in the database. /// public void MoveNext() { HasNext = dataReader.Read() || (dataReader.NextResult() && dataReader.Read()); } /// /// Reads a value at column from the database. /// /// The expected type of value in the column with name . /// The name of the column to read from. /// The read value from the column with name . /// Thrown when the value in the column was not of type . public T Read(string columnName) { return (T) dataReader[columnName]; } /// /// Reads the value in the column with name from the currently pointed row. /// /// The type of object to read. /// The name of the column to read from. /// The value in the column, or null if the value was . /// Thrown when the value in the column could not be casted to type . public T? ReadOrNull(string columnName) where T : struct { var valueObject = dataReader[columnName]; if (valueObject.Equals(DBNull.Value)) { return null; } return (T) valueObject; } /// /// Reads the current row into a new instance of . /// /// A new instance of , based upon the current row. /// Thrown when the database returned incorrect values for required properties. private HydraulicBoundaryLocation ReadHydraulicBoundaryLocation() { try { var id = Read(HydraulicBoundaryDatabaseColumns.LocationId); var name = Read(HydraulicBoundaryDatabaseColumns.LocationName); var x = Read(HydraulicBoundaryDatabaseColumns.LocationX); var y = Read(HydraulicBoundaryDatabaseColumns.LocationY); var designWaterLevel = ""; MoveNext(); return new HydraulicBoundaryLocation(id, name, x, y, designWaterLevel); } catch (InvalidCastException exception) { MoveNext(); throw; } } /// /// Prepares a new data reader with queries for obtaining the locations and updates the reader /// so that it points to the first row of the result set. /// private void InitializeReader() { PrepareReader(); MoveNext(); } /// /// Prepares the queries required for obtaining locations from the database. /// private void PrepareReader() { var versionQuery = string.Format("SELECT (NameRegion || CreationDate) as {0} FROM General LIMIT 0,1;", HydraulicBoundaryDatabaseColumns.Version); var countQuery = string.Format("SELECT count(*) as {0} FROM HRDLocations WHERE LocationTypeId > 1 ;", HydraulicBoundaryDatabaseColumns.LocationCount); var locationsQuery = string.Format( "SELECT HRDLocationId as {0}, Name as {1}, XCoordinate as {2}, YCoordinate as {3} FROM HRDLocations WHERE LocationTypeId > 1;", HydraulicBoundaryDatabaseColumns.LocationId, HydraulicBoundaryDatabaseColumns.LocationName, HydraulicBoundaryDatabaseColumns.LocationX, HydraulicBoundaryDatabaseColumns.LocationY); CreateDataReader(string.Join(" ", versionQuery, countQuery, locationsQuery), new SQLiteParameter { DbType = DbType.String }); } /// /// Creates a new data reader to use in this class. /// /// Thrown when /// /// Amount of locations in database could not be read. /// A query could not be executed on the database schema. /// /// private void CreateDataReader(string queryString, params SQLiteParameter[] parameters) { using (var query = new SQLiteCommand(Connection) { CommandText = queryString }) { query.Parameters.AddRange(parameters); try { dataReader = query.ExecuteReader(); GetVersion(); GetCount(); } catch (SQLiteException exception) { Dispose(); var message = new FileReaderErrorMessageBuilder(Path).Build(Resources.Error_HydraulicBoundaryLocation_read_from_database); throw new CriticalFileReadException(message, exception); } } } /// /// Gets the database version from the metadata table. /// private void GetVersion() { if (dataReader.Read()) { Version = Read(HydraulicBoundaryDatabaseColumns.Version); } dataReader.NextResult(); } /// /// Gets the amount of locations that can be read from the database. /// private void GetCount() { dataReader.Read(); Count = (int) Read(HydraulicBoundaryDatabaseColumns.LocationCount); dataReader.NextResult(); } } }