Mercurial > hg > orthanc
changeset 3080:1a75595d8e44 db-changes
started refactoring of ServerIndex::Store()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 03 Jan 2019 18:21:22 +0100 |
parents | 65e2bfa953ef |
children | 2e5970ddcfeb |
files | CMakeLists.txt OrthancServer/IDatabaseWrapper.h OrthancServer/SQLiteDatabaseWrapper.cpp OrthancServer/SQLiteDatabaseWrapper.h OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.h OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.cpp OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.h OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h Plugins/Engine/OrthancPluginDatabase.cpp Plugins/Engine/OrthancPluginDatabase.h UnitTestsSources/ServerIndexTests.cpp |
diffstat | 13 files changed, 585 insertions(+), 346 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Thu Jan 03 14:03:39 2019 +0100 +++ b/CMakeLists.txt Thu Jan 03 18:21:22 2019 +0100 @@ -73,6 +73,7 @@ OrthancServer/SQLiteDatabaseWrapper.cpp OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp OrthancServer/Search/Compatibility/DatabaseLookup.cpp + OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.cpp OrthancServer/Search/Compatibility/SetOfResources.cpp OrthancServer/Search/DatabaseConstraint.cpp OrthancServer/Search/DatabaseLookup.cpp
--- a/OrthancServer/IDatabaseWrapper.h Thu Jan 03 14:03:39 2019 +0100 +++ b/OrthancServer/IDatabaseWrapper.h Thu Jan 03 18:21:22 2019 +0100 @@ -66,6 +66,17 @@ }; + struct CreateInstanceResult + { + bool isNewPatient_; + bool isNewStudy_; + bool isNewSeries_; + int64_t patientId_; + int64_t studyId_; + int64_t seriesId_; + }; + + virtual ~IDatabaseWrapper() { } @@ -77,16 +88,10 @@ virtual void AddAttachment(int64_t id, const FileInfo& attachment) = 0; - virtual void AttachChild(int64_t parent, - int64_t child) = 0; - virtual void ClearChanges() = 0; virtual void ClearExportedResources() = 0; - virtual int64_t CreateResource(const std::string& publicId, - ResourceType type) = 0; - virtual void DeleteAttachment(int64_t id, FileContentType attachment) = 0; @@ -210,12 +215,28 @@ virtual void Upgrade(unsigned int targetVersion, IStorageArea& storageArea) = 0; + + /** + * Primitives introduced in Orthanc 1.5.2 + **/ + virtual bool IsDiskSizeAbove(uint64_t threshold) = 0; - + virtual void ApplyLookupResources(std::list<std::string>& resourcesId, std::list<std::string>* instancesId, // Can be NULL if not needed const std::vector<DatabaseConstraint>& lookup, ResourceType queryLevel, size_t limit) = 0; + + // Returns "true" iff. the instance already exists *and* + // "overwrite" is "false". If "false" is returned, the content of + // "result" is undefined, but "instanceId" must be properly set. + virtual bool CreateInstance(CreateInstanceResult& result, /* out */ + int64_t& instanceId, /* out */ + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance, + bool overwrite) = 0; }; }
--- a/OrthancServer/SQLiteDatabaseWrapper.cpp Thu Jan 03 14:03:39 2019 +0100 +++ b/OrthancServer/SQLiteDatabaseWrapper.cpp Thu Jan 03 18:21:22 2019 +0100 @@ -1248,8 +1248,6 @@ } { - printf("[%s]\n", sql.c_str()); - SQLite::Statement statement(db_, sql); formatter.Bind(statement); statement.Run();
--- a/OrthancServer/SQLiteDatabaseWrapper.h Thu Jan 03 14:03:39 2019 +0100 +++ b/OrthancServer/SQLiteDatabaseWrapper.h Thu Jan 03 18:21:22 2019 +0100 @@ -36,6 +36,7 @@ #include "IDatabaseWrapper.h" #include "../Core/SQLite/Connection.h" +#include "Search/Compatibility/ICompatibilityCreateInstance.h" namespace Orthanc { @@ -49,7 +50,9 @@ * translates low-level requests into SQL statements. Mutual * exclusion MUST be implemented at a higher level. **/ - class SQLiteDatabaseWrapper : public IDatabaseWrapper + class SQLiteDatabaseWrapper : + public IDatabaseWrapper, + public Compatibility::ICompatibilityCreateInstance { private: class Transaction; @@ -320,5 +323,17 @@ ResourceType queryLevel, size_t limit) ORTHANC_OVERRIDE; + + virtual bool CreateInstance(CreateInstanceResult& result, + int64_t& instanceId, + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance, + bool overwrite) + { + return ICompatibilityCreateInstance::Apply( + result, instanceId, *this, *this, patient, study, series, instance, overwrite); + } }; }
--- a/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp Thu Jan 03 14:03:39 2019 +0100 +++ b/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp Thu Jan 03 18:21:22 2019 +0100 @@ -40,14 +40,29 @@ { namespace Compatibility { - void CompatibilityDatabaseWrapper::ApplyLookupResources(std::list<std::string>& resourcesId, - std::list<std::string>* instancesId, - const std::vector<DatabaseConstraint>& lookup, - ResourceType queryLevel, - size_t limit) + void CompatibilityDatabaseWrapper::ApplyLookupResources( + std::list<std::string>& resourcesId, + std::list<std::string>* instancesId, + const std::vector<DatabaseConstraint>& lookup, + ResourceType queryLevel, + size_t limit) { Compatibility::DatabaseLookup compat(*this); compat.ApplyLookupResources(resourcesId, instancesId, lookup, queryLevel, limit); } + + + bool CompatibilityDatabaseWrapper::CreateInstance( + IDatabaseWrapper::CreateInstanceResult& result, + int64_t& instanceId, + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance, + bool overwrite) + { + return ICompatibilityCreateInstance::Apply + (result, instanceId, *this, *this, patient, study, series, instance, overwrite); + } } }
--- a/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.h Thu Jan 03 14:03:39 2019 +0100 +++ b/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.h Thu Jan 03 18:21:22 2019 +0100 @@ -33,7 +33,7 @@ #pragma once -#include "../../IDatabaseWrapper.h" +#include "ICompatibilityCreateInstance.h" namespace Orthanc { @@ -44,7 +44,9 @@ * that were used in Orthanc <= 1.5.1, and that have been removed * during the optimization of the database engine. **/ - class CompatibilityDatabaseWrapper : public IDatabaseWrapper + class CompatibilityDatabaseWrapper : + public IDatabaseWrapper, + public ICompatibilityCreateInstance { public: virtual void ApplyLookupResources(std::list<std::string>& resourcesId, @@ -54,9 +56,18 @@ size_t limit) ORTHANC_OVERRIDE; + virtual bool CreateInstance(CreateInstanceResult& result, + int64_t& instanceId, + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance, + bool overwrite) + ORTHANC_OVERRIDE; + virtual void GetAllInternalIds(std::list<int64_t>& target, ResourceType resourceType) = 0; - + virtual void LookupIdentifier(std::list<int64_t>& result, ResourceType level, const DicomTag& tag,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.cpp Thu Jan 03 18:21:22 2019 +0100 @@ -0,0 +1,167 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program 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. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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 <http://www.gnu.org/licenses/>. + **/ + + +#include "../../PrecompiledHeadersServer.h" +#include "ICompatibilityCreateInstance.h" + +#include "../../../Core/OrthancException.h" + +namespace Orthanc +{ + namespace Compatibility + { + bool ICompatibilityCreateInstance::Apply(IDatabaseWrapper::CreateInstanceResult& result, + int64_t& instanceId, + ICompatibilityCreateInstance& compatibility, + IDatabaseWrapper& database, + const std::string& hashPatient, + const std::string& hashStudy, + const std::string& hashSeries, + const std::string& hashInstance, + bool overwrite) + { + { + ResourceType type; + int64_t tmp; + + if (database.LookupResource(tmp, type, hashInstance)) + { + assert(type == ResourceType_Instance); + + if (overwrite) + { + // Overwrite the old instance + LOG(INFO) << "Overwriting instance: " << hashInstance; + database.DeleteResource(tmp); + } + else + { + // Do nothing if the instance already exists + instanceId = tmp; + return false; + } + } + } + + instanceId = compatibility.CreateResource(hashInstance, ResourceType_Instance); + + result.isNewPatient_ = false; + result.isNewStudy_ = false; + result.isNewSeries_ = false; + result.patientId_ = -1; + result.studyId_ = -1; + result.seriesId_ = -1; + + // Detect up to which level the patient/study/series/instance + // hierarchy must be created + + { + ResourceType dummy; + + if (database.LookupResource(result.seriesId_, dummy, hashSeries)) + { + assert(dummy == ResourceType_Series); + // The patient, the study and the series already exist + + bool ok = (database.LookupResource(result.patientId_, dummy, hashPatient) && + database.LookupResource(result.studyId_, dummy, hashStudy)); + assert(ok); + } + else if (database.LookupResource(result.studyId_, dummy, hashStudy)) + { + assert(dummy == ResourceType_Study); + + // New series: The patient and the study already exist + result.isNewSeries_ = true; + + bool ok = database.LookupResource(result.patientId_, dummy, hashPatient); + assert(ok); + } + else if (database.LookupResource(result.patientId_, dummy, hashPatient)) + { + assert(dummy == ResourceType_Patient); + + // New study and series: The patient already exist + result.isNewStudy_ = true; + result.isNewSeries_ = true; + } + else + { + // New patient, study and series: Nothing exists + result.isNewPatient_ = true; + result.isNewStudy_ = true; + result.isNewSeries_ = true; + } + } + + // Create the series if needed + if (result.isNewSeries_) + { + result.seriesId_ = compatibility.CreateResource(hashSeries, ResourceType_Series); + } + + // Create the study if needed + if (result.isNewStudy_) + { + result.studyId_ = compatibility.CreateResource(hashStudy, ResourceType_Study); + } + + // Create the patient if needed + if (result.isNewPatient_) + { + result.patientId_ = compatibility.CreateResource(hashPatient, ResourceType_Patient); + } + + // Create the parent-to-child links + compatibility.AttachChild(result.seriesId_, instanceId); + + if (result.isNewSeries_) + { + compatibility.AttachChild(result.studyId_, result.seriesId_); + } + + if (result.isNewStudy_) + { + compatibility.AttachChild(result.patientId_, result.studyId_); + } + + // Sanity checks + assert(result.patientId_ != -1); + assert(result.studyId_ != -1); + assert(result.seriesId_ != -1); + assert(instanceId != -1); + + return true; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.h Thu Jan 03 18:21:22 2019 +0100 @@ -0,0 +1,62 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program 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. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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 <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../../IDatabaseWrapper.h" + +namespace Orthanc +{ + namespace Compatibility + { + class ICompatibilityCreateInstance : public boost::noncopyable + { + public: + virtual int64_t CreateResource(const std::string& publicId, + ResourceType type) = 0; + + virtual void AttachChild(int64_t parent, + int64_t child) = 0; + + static bool Apply(IDatabaseWrapper::CreateInstanceResult& result, + int64_t& instanceId, + ICompatibilityCreateInstance& compatibility, + IDatabaseWrapper& database, + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance, + bool overwrite); + }; + } +}
--- a/OrthancServer/ServerIndex.cpp Thu Jan 03 14:03:39 2019 +0100 +++ b/OrthancServer/ServerIndex.cpp Thu Jan 03 18:21:22 2019 +0100 @@ -612,44 +612,6 @@ - int64_t ServerIndex::CreateResource(const std::string& publicId, - ResourceType type) - { - int64_t id = db_.CreateResource(publicId, type); - - ChangeType changeType; - switch (type) - { - case ResourceType_Patient: - changeType = ChangeType_NewPatient; - break; - - case ResourceType_Study: - changeType = ChangeType_NewStudy; - break; - - case ResourceType_Series: - changeType = ChangeType_NewSeries; - break; - - case ResourceType_Instance: - changeType = ChangeType_NewInstance; - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - ServerIndexChange change(changeType, type, publicId); - db_.LogChange(id, change); - - assert(listener_.get() != NULL); - listener_->SignalChange(change); - - return id; - } - - ServerIndex::ServerIndex(ServerContext& context, IDatabaseWrapper& db, unsigned int threadSleep) : @@ -720,7 +682,19 @@ } - + void ServerIndex::SignalNewResource(ChangeType changeType, + ResourceType level, + const std::string& publicId, + int64_t internalId) + { + ServerIndexChange change(changeType, level, publicId); + db_.LogChange(internalId, change); + + assert(listener_.get() != NULL); + listener_->SignalChange(change); + } + + StoreStatus ServerIndex::Store(std::map<MetadataType, std::string>& instanceMetadata, DicomInstanceToStore& instanceToStore, const Attachments& attachments) @@ -732,33 +706,47 @@ instanceMetadata.clear(); + const std::string hashPatient = instanceToStore.GetHasher().HashPatient(); + const std::string hashStudy = instanceToStore.GetHasher().HashStudy(); + const std::string hashSeries = instanceToStore.GetHasher().HashSeries(); + const std::string hashInstance = instanceToStore.GetHasher().HashInstance(); + try { Transaction t(*this); + IDatabaseWrapper::CreateInstanceResult status; + int64_t instanceId; + // Check whether this instance is already stored + if (!db_.CreateInstance(status, instanceId, hashPatient, + hashStudy, hashSeries, hashInstance, overwrite_)) { - ResourceType type; - int64_t tmp; - if (db_.LookupResource(tmp, type, instanceToStore.GetHasher().HashInstance())) - { - assert(type == ResourceType_Instance); - - if (overwrite_) - { - // Overwrite the old instance - LOG(INFO) << "Overwriting instance: " << instanceToStore.GetHasher().HashInstance(); - db_.DeleteResource(tmp); - } - else - { - // Do nothing if the instance already exists - db_.GetAllMetadata(instanceMetadata, tmp); - return StoreStatus_AlreadyStored; - } - } + // Do nothing if the instance already exists and overwriting is disabled + db_.GetAllMetadata(instanceMetadata, instanceId); + return StoreStatus_AlreadyStored; + } + + + // Warn about the creation of new resources. The order must be from instance to patient. + SignalNewResource(ChangeType_NewInstance, ResourceType_Instance, hashInstance, instanceId); + + if (status.isNewSeries_) + { + SignalNewResource(ChangeType_NewSeries, ResourceType_Series, hashSeries, status.seriesId_); } - + + if (status.isNewStudy_) + { + SignalNewResource(ChangeType_NewStudy, ResourceType_Study, hashStudy, status.studyId_); + } + + if (status.isNewPatient_) + { + SignalNewResource(ChangeType_NewPatient, ResourceType_Patient, hashPatient, status.patientId_); + } + + // Ensure there is enough room in the storage for the new instance uint64_t instanceSize = 0; for (Attachments::const_iterator it = attachments.begin(); @@ -767,125 +755,59 @@ instanceSize += it->GetCompressedSize(); } - Recycle(instanceSize, instanceToStore.GetHasher().HashPatient()); - - // Create the instance - int64_t instance = CreateResource(instanceToStore.GetHasher().HashInstance(), ResourceType_Instance); - ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary); - - // Detect up to which level the patient/study/series/instance - // hierarchy must be created - int64_t patient = -1, study = -1, series = -1; - bool isNewPatient = false; - bool isNewStudy = false; - bool isNewSeries = false; - + Recycle(instanceSize, hashPatient /* don't consider the current patient for recycling */); + + + // Populate the newly-created resources + // TODO - GROUP THIS + + ServerToolbox::StoreMainDicomTags(db_, instanceId, ResourceType_Instance, dicomSummary); + + if (status.isNewSeries_) { - ResourceType dummy; - - if (db_.LookupResource(series, dummy, instanceToStore.GetHasher().HashSeries())) - { - assert(dummy == ResourceType_Series); - // The patient, the study and the series already exist - - bool ok = (db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient()) && - db_.LookupResource(study, dummy, instanceToStore.GetHasher().HashStudy())); - assert(ok); - } - else if (db_.LookupResource(study, dummy, instanceToStore.GetHasher().HashStudy())) - { - assert(dummy == ResourceType_Study); - - // New series: The patient and the study already exist - isNewSeries = true; - - bool ok = db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient()); - assert(ok); - } - else if (db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient())) - { - assert(dummy == ResourceType_Patient); - - // New study and series: The patient already exist - isNewStudy = true; - isNewSeries = true; - } - else - { - // New patient, study and series: Nothing exists - isNewPatient = true; - isNewStudy = true; - isNewSeries = true; - } + ServerToolbox::StoreMainDicomTags(db_, status.seriesId_, ResourceType_Series, dicomSummary); + } + + if (status.isNewStudy_) + { + ServerToolbox::StoreMainDicomTags(db_, status.studyId_, ResourceType_Study, dicomSummary); } - // Create the series if needed - if (isNewSeries) - { - series = CreateResource(instanceToStore.GetHasher().HashSeries(), ResourceType_Series); - ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, dicomSummary); - } - - // Create the study if needed - if (isNewStudy) + if (status.isNewPatient_) { - study = CreateResource(instanceToStore.GetHasher().HashStudy(), ResourceType_Study); - ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, dicomSummary); - } - - // Create the patient if needed - if (isNewPatient) - { - patient = CreateResource(instanceToStore.GetHasher().HashPatient(), ResourceType_Patient); - ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary); + ServerToolbox::StoreMainDicomTags(db_, status.patientId_, ResourceType_Patient, dicomSummary); } - // Create the parent-to-child links - db_.AttachChild(series, instance); - - if (isNewSeries) - { - db_.AttachChild(study, series); - } - - if (isNewStudy) - { - db_.AttachChild(patient, study); - } - - // Sanity checks - assert(patient != -1); - assert(study != -1); - assert(series != -1); - assert(instance != -1); - + // Attach the files to the newly created instance for (Attachments::const_iterator it = attachments.begin(); it != attachments.end(); ++it) { - db_.AddAttachment(instance, *it); + db_.AddAttachment(instanceId, *it); } + // Attach the user-specified metadata + // TODO - GROUP THIS for (MetadataMap::const_iterator it = metadata.begin(); it != metadata.end(); ++it) { switch (it->first.first) { case ResourceType_Patient: - db_.SetMetadata(patient, it->first.second, it->second); + db_.SetMetadata(status.patientId_, it->first.second, it->second); break; case ResourceType_Study: - db_.SetMetadata(study, it->first.second, it->second); + db_.SetMetadata(status.studyId_, it->first.second, it->second); break; case ResourceType_Series: - db_.SetMetadata(series, it->first.second, it->second); + db_.SetMetadata(status.seriesId_, it->first.second, it->second); break; case ResourceType_Instance: - SetInstanceMetadata(instanceMetadata, instance, it->first.second, it->second); + SetInstanceMetadata(instanceMetadata, instanceId, it->first.second, it->second); break; default: @@ -895,16 +817,16 @@ // Attach the auto-computed metadata for the patient/study/series levels std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); - db_.SetMetadata(series, MetadataType_LastUpdate, now); - db_.SetMetadata(study, MetadataType_LastUpdate, now); - db_.SetMetadata(patient, MetadataType_LastUpdate, now); + db_.SetMetadata(status.seriesId_, MetadataType_LastUpdate, now); + db_.SetMetadata(status.studyId_, MetadataType_LastUpdate, now); + db_.SetMetadata(status.patientId_, MetadataType_LastUpdate, now); // Attach the auto-computed metadata for the instance level, // reflecting these additions into the input metadata map - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_ReceptionDate, now); - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteAet, + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_ReceptionDate, now); + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_RemoteAet, instanceToStore.GetOrigin().GetRemoteAetC()); - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_Origin, + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_Origin, EnumerationToString(instanceToStore.GetOrigin().GetRequestOrigin())); { @@ -913,25 +835,25 @@ if (instanceToStore.LookupTransferSyntax(s)) { // New in Orthanc 1.2.0 - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_TransferSyntax, s); + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_TransferSyntax, s); } if (instanceToStore.GetOrigin().LookupRemoteIp(s)) { // New in Orthanc 1.4.0 - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteIp, s); + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_RemoteIp, s); } if (instanceToStore.GetOrigin().LookupCalledAet(s)) { // New in Orthanc 1.4.0 - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_CalledAet, s); + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_CalledAet, s); } if (instanceToStore.GetOrigin().LookupHttpUsername(s)) { // New in Orthanc 1.4.0 - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_HttpUsername, s); + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_HttpUsername, s); } } @@ -940,7 +862,7 @@ !value->IsNull() && !value->IsBinary()) { - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_SopClassUid, value->GetContent()); + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_SopClassUid, value->GetContent()); } if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || @@ -949,26 +871,26 @@ if (!value->IsNull() && !value->IsBinary()) { - SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_IndexInSeries, value->GetContent()); + SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_IndexInSeries, value->GetContent()); } } // Check whether the series of this new instance is now completed - if (isNewSeries) + if (status.isNewSeries_) { - ComputeExpectedNumberOfInstances(db_, series, dicomSummary); + ComputeExpectedNumberOfInstances(db_, status.seriesId_, dicomSummary); } - SeriesStatus seriesStatus = GetSeriesStatus(series); + SeriesStatus seriesStatus = GetSeriesStatus(status.seriesId_); if (seriesStatus == SeriesStatus_Complete) { - LogChange(series, ChangeType_CompletedSeries, ResourceType_Series, instanceToStore.GetHasher().HashSeries()); + LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries); } // Mark the parent resources of this instance as unstable - MarkAsUnstable(series, ResourceType_Series, instanceToStore.GetHasher().HashSeries()); - MarkAsUnstable(study, ResourceType_Study, instanceToStore.GetHasher().HashStudy()); - MarkAsUnstable(patient, ResourceType_Patient, instanceToStore.GetHasher().HashPatient()); + MarkAsUnstable(status.seriesId_, ResourceType_Series, hashSeries); + MarkAsUnstable(status.studyId_, ResourceType_Study, hashStudy); + MarkAsUnstable(status.patientId_, ResourceType_Patient, hashPatient); t.Commit(instanceSize);
--- a/OrthancServer/ServerIndex.h Thu Jan 03 14:03:39 2019 +0100 +++ b/OrthancServer/ServerIndex.h Thu Jan 03 18:21:22 2019 +0100 @@ -116,10 +116,12 @@ ResourceType resourceType, const std::string& publicId); - uint64_t IncrementGlobalSequenceInternal(GlobalProperty property); + void SignalNewResource(ChangeType changeType, + ResourceType level, + const std::string& publicId, + int64_t internalId); - int64_t CreateResource(const std::string& publicId, - ResourceType type); + uint64_t IncrementGlobalSequenceInternal(GlobalProperty property); void SetInstanceMetadata(std::map<MetadataType, std::string>& instanceMetadata, int64_t instance,
--- a/Plugins/Engine/OrthancPluginDatabase.cpp Thu Jan 03 14:03:39 2019 +0100 +++ b/Plugins/Engine/OrthancPluginDatabase.cpp Thu Jan 03 18:21:22 2019 +0100 @@ -1189,6 +1189,22 @@ } + bool OrthancPluginDatabase::CreateInstance( + IDatabaseWrapper::CreateInstanceResult& result, + int64_t& instanceId, + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance, + bool overwrite) + { + // TODO optimized version + + return CompatibilityDatabaseWrapper::CreateInstance( + result, instanceId, patient, study, series, instance, overwrite); + } + + void OrthancPluginDatabase::LookupIdentifier(std::list<int64_t>& result, ResourceType level, const DicomTag& tag,
--- a/Plugins/Engine/OrthancPluginDatabase.h Thu Jan 03 14:03:39 2019 +0100 +++ b/Plugins/Engine/OrthancPluginDatabase.h Thu Jan 03 18:21:22 2019 +0100 @@ -316,6 +316,15 @@ size_t limit) ORTHANC_OVERRIDE; + virtual bool CreateInstance(CreateInstanceResult& result, + int64_t& instanceId, + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance, + bool overwrite) + ORTHANC_OVERRIDE; + // From the "CompatibilityDatabaseWrapper" interface virtual void GetAllInternalIds(std::list<int64_t>& target, ResourceType resourceType)
--- a/UnitTestsSources/ServerIndexTests.cpp Thu Jan 03 14:03:39 2019 +0100 +++ b/UnitTestsSources/ServerIndexTests.cpp Thu Jan 03 18:21:22 2019 +0100 @@ -297,65 +297,65 @@ TEST_P(DatabaseWrapperTest, Simple) { int64_t a[] = { - index_->CreateResource("a", ResourceType_Patient), // 0 - index_->CreateResource("b", ResourceType_Study), // 1 - index_->CreateResource("c", ResourceType_Series), // 2 - index_->CreateResource("d", ResourceType_Instance), // 3 - index_->CreateResource("e", ResourceType_Instance), // 4 - index_->CreateResource("f", ResourceType_Instance), // 5 - index_->CreateResource("g", ResourceType_Study) // 6 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("a", ResourceType_Patient), // 0 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("b", ResourceType_Study), // 1 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("c", ResourceType_Series), // 2 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("d", ResourceType_Instance), // 3 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("e", ResourceType_Instance), // 4 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("f", ResourceType_Instance), // 5 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("g", ResourceType_Study) // 6 }; - ASSERT_EQ("a", index_->GetPublicId(a[0])); - ASSERT_EQ("b", index_->GetPublicId(a[1])); - ASSERT_EQ("c", index_->GetPublicId(a[2])); - ASSERT_EQ("d", index_->GetPublicId(a[3])); - ASSERT_EQ("e", index_->GetPublicId(a[4])); - ASSERT_EQ("f", index_->GetPublicId(a[5])); - ASSERT_EQ("g", index_->GetPublicId(a[6])); + ASSERT_EQ("a", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[0])); + ASSERT_EQ("b", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[1])); + ASSERT_EQ("c", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[2])); + ASSERT_EQ("d", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[3])); + ASSERT_EQ("e", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[4])); + ASSERT_EQ("f", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[5])); + ASSERT_EQ("g", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[6])); - ASSERT_EQ(ResourceType_Patient, index_->GetResourceType(a[0])); - ASSERT_EQ(ResourceType_Study, index_->GetResourceType(a[1])); - ASSERT_EQ(ResourceType_Series, index_->GetResourceType(a[2])); - ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[3])); - ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[4])); - ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[5])); - ASSERT_EQ(ResourceType_Study, index_->GetResourceType(a[6])); + ASSERT_EQ(ResourceType_Patient, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[0])); + ASSERT_EQ(ResourceType_Study, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[1])); + ASSERT_EQ(ResourceType_Series, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[2])); + ASSERT_EQ(ResourceType_Instance, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[3])); + ASSERT_EQ(ResourceType_Instance, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[4])); + ASSERT_EQ(ResourceType_Instance, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[5])); + ASSERT_EQ(ResourceType_Study, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[6])); { std::list<std::string> t; - index_->GetAllPublicIds(t, ResourceType_Patient); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Patient); ASSERT_EQ(1u, t.size()); ASSERT_EQ("a", t.front()); - index_->GetAllPublicIds(t, ResourceType_Series); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Series); ASSERT_EQ(1u, t.size()); ASSERT_EQ("c", t.front()); - index_->GetAllPublicIds(t, ResourceType_Study); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Study); ASSERT_EQ(2u, t.size()); - index_->GetAllPublicIds(t, ResourceType_Instance); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Instance); ASSERT_EQ(3u, t.size()); } - index_->SetGlobalProperty(GlobalProperty_FlushSleep, "World"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetGlobalProperty(GlobalProperty_FlushSleep, "World"); - index_->AttachChild(a[0], a[1]); - index_->AttachChild(a[1], a[2]); - index_->AttachChild(a[2], a[3]); - index_->AttachChild(a[2], a[4]); - index_->AttachChild(a[6], a[5]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[0], a[1]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[1], a[2]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[3]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[6], a[5]); int64_t parent; - ASSERT_FALSE(index_->LookupParent(parent, a[0])); - ASSERT_TRUE(index_->LookupParent(parent, a[1])); ASSERT_EQ(a[0], parent); - ASSERT_TRUE(index_->LookupParent(parent, a[2])); ASSERT_EQ(a[1], parent); - ASSERT_TRUE(index_->LookupParent(parent, a[3])); ASSERT_EQ(a[2], parent); - ASSERT_TRUE(index_->LookupParent(parent, a[4])); ASSERT_EQ(a[2], parent); - ASSERT_TRUE(index_->LookupParent(parent, a[5])); ASSERT_EQ(a[6], parent); - ASSERT_FALSE(index_->LookupParent(parent, a[6])); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[0])); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[1])); ASSERT_EQ(a[0], parent); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[2])); ASSERT_EQ(a[1], parent); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[3])); ASSERT_EQ(a[2], parent); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[4])); ASSERT_EQ(a[2], parent); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[5])); ASSERT_EQ(a[6], parent); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[6])); std::string s; @@ -368,14 +368,14 @@ CheckParentPublicId("g", a[5]); std::list<std::string> l; - index_->GetChildrenPublicId(l, a[0]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("b", l.front()); - index_->GetChildrenPublicId(l, a[1]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("c", l.front()); - index_->GetChildrenPublicId(l, a[3]); ASSERT_EQ(0u, l.size()); - index_->GetChildrenPublicId(l, a[4]); ASSERT_EQ(0u, l.size()); - index_->GetChildrenPublicId(l, a[5]); ASSERT_EQ(0u, l.size()); - index_->GetChildrenPublicId(l, a[6]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("f", l.front()); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[0]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("b", l.front()); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[1]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("c", l.front()); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[3]); ASSERT_EQ(0u, l.size()); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[4]); ASSERT_EQ(0u, l.size()); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[5]); ASSERT_EQ(0u, l.size()); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[6]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("f", l.front()); - index_->GetChildrenPublicId(l, a[2]); ASSERT_EQ(2u, l.size()); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[2]); ASSERT_EQ(2u, l.size()); if (l.front() == "d") { ASSERT_EQ("e", l.back()); @@ -387,64 +387,64 @@ } std::list<MetadataType> md; - index_->ListAvailableMetadata(md, a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]); ASSERT_EQ(0u, md.size()); - index_->AddAttachment(a[4], FileInfo("my json file", FileContentType_DicomAsJson, 42, "md5", + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(a[4], FileInfo("my json file", FileContentType_DicomAsJson, 42, "md5", CompressionType_ZlibWithSize, 21, "compressedMD5")); - index_->AddAttachment(a[4], FileInfo("my dicom file", FileContentType_Dicom, 42, "md5")); - index_->AddAttachment(a[6], FileInfo("world", FileContentType_Dicom, 44, "md5")); - index_->SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(a[4], FileInfo("my dicom file", FileContentType_Dicom, 42, "md5")); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(a[6], FileInfo("world", FileContentType_Dicom, 44, "md5")); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE"); - index_->ListAvailableMetadata(md, a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]); ASSERT_EQ(1u, md.size()); ASSERT_EQ(MetadataType_Instance_RemoteAet, md.front()); - index_->SetMetadata(a[4], MetadataType_ModifiedFrom, "TUTU"); - index_->ListAvailableMetadata(md, a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetMetadata(a[4], MetadataType_ModifiedFrom, "TUTU"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]); ASSERT_EQ(2u, md.size()); std::map<MetadataType, std::string> md2; - index_->GetAllMetadata(md2, a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllMetadata(md2, a[4]); ASSERT_EQ(2u, md2.size()); ASSERT_EQ("TUTU", md2[MetadataType_ModifiedFrom]); ASSERT_EQ("PINNACLE", md2[MetadataType_Instance_RemoteAet]); - index_->DeleteMetadata(a[4], MetadataType_ModifiedFrom); - index_->ListAvailableMetadata(md, a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteMetadata(a[4], MetadataType_ModifiedFrom); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]); ASSERT_EQ(1u, md.size()); ASSERT_EQ(MetadataType_Instance_RemoteAet, md.front()); - index_->GetAllMetadata(md2, a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllMetadata(md2, a[4]); ASSERT_EQ(1u, md2.size()); ASSERT_EQ("PINNACLE", md2[MetadataType_Instance_RemoteAet]); - ASSERT_EQ(21u + 42u + 44u, index_->GetTotalCompressedSize()); - ASSERT_EQ(42u + 42u + 44u, index_->GetTotalUncompressedSize()); + ASSERT_EQ(21u + 42u + 44u, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetTotalCompressedSize()); + ASSERT_EQ(42u + 42u + 44u, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetTotalUncompressedSize()); - index_->SetMainDicomTag(a[3], DicomTag(0x0010, 0x0010), "PatientName"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetMainDicomTag(a[3], DicomTag(0x0010, 0x0010), "PatientName"); int64_t b; ResourceType t; - ASSERT_TRUE(index_->LookupResource(b, t, "g")); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupResource(b, t, "g")); ASSERT_EQ(7, b); ASSERT_EQ(ResourceType_Study, t); - ASSERT_TRUE(index_->LookupMetadata(s, a[4], MetadataType_Instance_RemoteAet)); - ASSERT_FALSE(index_->LookupMetadata(s, a[4], MetadataType_Instance_IndexInSeries)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(s, a[4], MetadataType_Instance_RemoteAet)); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(s, a[4], MetadataType_Instance_IndexInSeries)); ASSERT_EQ("PINNACLE", s); std::string u; - ASSERT_TRUE(index_->LookupMetadata(u, a[4], MetadataType_Instance_RemoteAet)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(u, a[4], MetadataType_Instance_RemoteAet)); ASSERT_EQ("PINNACLE", u); - ASSERT_FALSE(index_->LookupMetadata(u, a[4], MetadataType_Instance_IndexInSeries)); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(u, a[4], MetadataType_Instance_IndexInSeries)); - ASSERT_TRUE(index_->LookupGlobalProperty(s, GlobalProperty_FlushSleep)); - ASSERT_FALSE(index_->LookupGlobalProperty(s, static_cast<GlobalProperty>(42))); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(s, GlobalProperty_FlushSleep)); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(s, static_cast<GlobalProperty>(42))); ASSERT_EQ("World", s); FileInfo att; - ASSERT_TRUE(index_->LookupAttachment(att, a[4], FileContentType_DicomAsJson)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupAttachment(att, a[4], FileContentType_DicomAsJson)); ASSERT_EQ("my json file", att.GetUuid()); ASSERT_EQ(21u, att.GetCompressedSize()); ASSERT_EQ("md5", att.GetUncompressedMD5()); @@ -452,7 +452,7 @@ ASSERT_EQ(42u, att.GetUncompressedSize()); ASSERT_EQ(CompressionType_ZlibWithSize, att.GetCompressionType()); - ASSERT_TRUE(index_->LookupAttachment(att, a[6], FileContentType_Dicom)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupAttachment(att, a[6], FileContentType_Dicom)); ASSERT_EQ("world", att.GetUuid()); ASSERT_EQ(44u, att.GetCompressedSize()); ASSERT_EQ("md5", att.GetUncompressedMD5()); @@ -468,7 +468,7 @@ CheckTableRecordCount(1, "Metadata"); CheckTableRecordCount(1, "MainDicomTags"); - index_->DeleteResource(a[0]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[0]); ASSERT_EQ(5u, listener_->deletedResources_.size()); ASSERT_EQ(2u, listener_->deletedFiles_.size()); ASSERT_FALSE(std::find(listener_->deletedFiles_.begin(), @@ -483,7 +483,7 @@ CheckTableRecordCount(1, "AttachedFiles"); CheckTableRecordCount(0, "MainDicomTags"); - index_->DeleteResource(a[5]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[5]); ASSERT_EQ(7u, listener_->deletedResources_.size()); CheckTableRecordCount(0, "Resources"); @@ -491,11 +491,11 @@ CheckTableRecordCount(3, "GlobalProperties"); std::string tmp; - ASSERT_TRUE(index_->LookupGlobalProperty(tmp, GlobalProperty_DatabaseSchemaVersion)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(tmp, GlobalProperty_DatabaseSchemaVersion)); ASSERT_EQ("6", tmp); - ASSERT_TRUE(index_->LookupGlobalProperty(tmp, GlobalProperty_FlushSleep)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(tmp, GlobalProperty_FlushSleep)); ASSERT_EQ("World", tmp); - ASSERT_TRUE(index_->LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast)); ASSERT_EQ("1", tmp); ASSERT_EQ(3u, listener_->deletedFiles_.size()); @@ -510,23 +510,23 @@ TEST_P(DatabaseWrapperTest, Upward) { int64_t a[] = { - index_->CreateResource("a", ResourceType_Patient), // 0 - index_->CreateResource("b", ResourceType_Study), // 1 - index_->CreateResource("c", ResourceType_Series), // 2 - index_->CreateResource("d", ResourceType_Instance), // 3 - index_->CreateResource("e", ResourceType_Instance), // 4 - index_->CreateResource("f", ResourceType_Study), // 5 - index_->CreateResource("g", ResourceType_Series), // 6 - index_->CreateResource("h", ResourceType_Series) // 7 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("a", ResourceType_Patient), // 0 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("b", ResourceType_Study), // 1 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("c", ResourceType_Series), // 2 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("d", ResourceType_Instance), // 3 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("e", ResourceType_Instance), // 4 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("f", ResourceType_Study), // 5 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("g", ResourceType_Series), // 6 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("h", ResourceType_Series) // 7 }; - index_->AttachChild(a[0], a[1]); - index_->AttachChild(a[1], a[2]); - index_->AttachChild(a[2], a[3]); - index_->AttachChild(a[2], a[4]); - index_->AttachChild(a[1], a[6]); - index_->AttachChild(a[0], a[5]); - index_->AttachChild(a[5], a[7]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[0], a[1]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[1], a[2]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[3]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[1], a[6]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[0], a[5]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[5], a[7]); CheckTwoChildren("b", "f", a[0]); CheckTwoChildren("c", "g", a[1]); @@ -538,22 +538,22 @@ CheckNoChild(a[7]); listener_->Reset(); - index_->DeleteResource(a[3]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[3]); ASSERT_EQ("c", listener_->ancestorId_); ASSERT_EQ(ResourceType_Series, listener_->ancestorType_); listener_->Reset(); - index_->DeleteResource(a[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[4]); ASSERT_EQ("b", listener_->ancestorId_); ASSERT_EQ(ResourceType_Study, listener_->ancestorType_); listener_->Reset(); - index_->DeleteResource(a[7]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[7]); ASSERT_EQ("a", listener_->ancestorId_); ASSERT_EQ(ResourceType_Patient, listener_->ancestorType_); listener_->Reset(); - index_->DeleteResource(a[6]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[6]); ASSERT_EQ("", listener_->ancestorId_); // No more ancestor } @@ -564,10 +564,10 @@ for (int i = 0; i < 10; i++) { std::string p = "Patient " + boost::lexical_cast<std::string>(i); - patients.push_back(index_->CreateResource(p, ResourceType_Patient)); - index_->AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10, + patients.push_back(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource(p, ResourceType_Patient)); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10, "md5-" + boost::lexical_cast<std::string>(i))); - ASSERT_FALSE(index_->IsProtectedPatient(patients[i])); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[i])); } CheckTableRecordCount(10u, "Resources"); @@ -576,8 +576,8 @@ listener_->Reset(); ASSERT_EQ(0u, listener_->deletedResources_.size()); - index_->DeleteResource(patients[5]); - index_->DeleteResource(patients[0]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(patients[5]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(patients[0]); ASSERT_EQ(2u, listener_->deletedResources_.size()); CheckTableRecordCount(8u, "Resources"); @@ -588,28 +588,28 @@ ASSERT_EQ("Patient 0", listener_->deletedFiles_[1]); int64_t p; - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(3u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(4u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(5u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(6u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[6]); - index_->DeleteResource(p); - index_->DeleteResource(patients[8]); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[6]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(patients[8]); ASSERT_EQ(8u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[7]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[7]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(9u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[9]); - index_->DeleteResource(p); - ASSERT_FALSE(index_->SelectPatientToRecycle(p)); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[9]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(10u, listener_->deletedResources_.size()); ASSERT_EQ(10u, listener_->deletedFiles_.size()); @@ -625,39 +625,39 @@ for (int i = 0; i < 5; i++) { std::string p = "Patient " + boost::lexical_cast<std::string>(i); - patients.push_back(index_->CreateResource(p, ResourceType_Patient)); - index_->AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10, + patients.push_back(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource(p, ResourceType_Patient)); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10, "md5-" + boost::lexical_cast<std::string>(i))); - ASSERT_FALSE(index_->IsProtectedPatient(patients[i])); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[i])); } CheckTableRecordCount(5, "Resources"); CheckTableRecordCount(5, "PatientRecyclingOrder"); - ASSERT_FALSE(index_->IsProtectedPatient(patients[2])); - index_->SetProtectedPatient(patients[2], true); - ASSERT_TRUE(index_->IsProtectedPatient(patients[2])); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2])); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], true); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2])); CheckTableRecordCount(5, "Resources"); CheckTableRecordCount(4, "PatientRecyclingOrder"); - index_->SetProtectedPatient(patients[2], true); - ASSERT_TRUE(index_->IsProtectedPatient(patients[2])); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], true); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2])); CheckTableRecordCount(4, "PatientRecyclingOrder"); - index_->SetProtectedPatient(patients[2], false); - ASSERT_FALSE(index_->IsProtectedPatient(patients[2])); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], false); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2])); CheckTableRecordCount(5, "PatientRecyclingOrder"); - index_->SetProtectedPatient(patients[2], false); - ASSERT_FALSE(index_->IsProtectedPatient(patients[2])); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], false); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2])); CheckTableRecordCount(5, "PatientRecyclingOrder"); CheckTableRecordCount(5, "Resources"); - index_->SetProtectedPatient(patients[2], true); - ASSERT_TRUE(index_->IsProtectedPatient(patients[2])); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], true); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2])); CheckTableRecordCount(4, "PatientRecyclingOrder"); - index_->SetProtectedPatient(patients[2], false); - ASSERT_FALSE(index_->IsProtectedPatient(patients[2])); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], false); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2])); CheckTableRecordCount(5, "PatientRecyclingOrder"); - index_->SetProtectedPatient(patients[3], true); - ASSERT_TRUE(index_->IsProtectedPatient(patients[3])); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[3], true); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[3])); CheckTableRecordCount(4, "PatientRecyclingOrder"); CheckTableRecordCount(5, "Resources"); @@ -666,33 +666,33 @@ // Unprotecting a patient puts it at the last position in the recycling queue int64_t p; ASSERT_EQ(0u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[0]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[0]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(1u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p, patients[1])); ASSERT_EQ(p, patients[4]); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[1])); ASSERT_EQ(p, patients[4]); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(2u, listener_->deletedResources_.size()); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]); - index_->DeleteResource(p); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(3u, listener_->deletedResources_.size()); - ASSERT_FALSE(index_->SelectPatientToRecycle(p, patients[2])); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]); - index_->DeleteResource(p); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[2])); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(4u, listener_->deletedResources_.size()); // "patients[3]" is still protected - ASSERT_FALSE(index_->SelectPatientToRecycle(p)); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(4u, listener_->deletedFiles_.size()); CheckTableRecordCount(1, "Resources"); CheckTableRecordCount(0, "PatientRecyclingOrder"); - index_->SetProtectedPatient(patients[3], false); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[3], false); CheckTableRecordCount(1, "PatientRecyclingOrder"); - ASSERT_FALSE(index_->SelectPatientToRecycle(p, patients[3])); - ASSERT_TRUE(index_->SelectPatientToRecycle(p, patients[2])); - ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]); - index_->DeleteResource(p); + ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[3])); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[2])); + ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p); ASSERT_EQ(5u, listener_->deletedResources_.size()); ASSERT_EQ(5u, listener_->deletedFiles_.size()); @@ -729,16 +729,16 @@ TEST_P(DatabaseWrapperTest, LookupIdentifier) { int64_t a[] = { - index_->CreateResource("a", ResourceType_Study), // 0 - index_->CreateResource("b", ResourceType_Study), // 1 - index_->CreateResource("c", ResourceType_Study), // 2 - index_->CreateResource("d", ResourceType_Series) // 3 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("a", ResourceType_Study), // 0 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("b", ResourceType_Study), // 1 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("c", ResourceType_Study), // 2 + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("d", ResourceType_Series) // 3 }; - index_->SetIdentifierTag(a[0], DICOM_TAG_STUDY_INSTANCE_UID, "0"); - index_->SetIdentifierTag(a[1], DICOM_TAG_STUDY_INSTANCE_UID, "1"); - index_->SetIdentifierTag(a[2], DICOM_TAG_STUDY_INSTANCE_UID, "0"); - index_->SetIdentifierTag(a[3], DICOM_TAG_SERIES_INSTANCE_UID, "0"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[0], DICOM_TAG_STUDY_INSTANCE_UID, "0"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[1], DICOM_TAG_STUDY_INSTANCE_UID, "1"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[2], DICOM_TAG_STUDY_INSTANCE_UID, "0"); + dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[3], DICOM_TAG_SERIES_INSTANCE_UID, "0"); std::list<std::string> s;