changeset 1709:2ad22b2970a2 db-changes

SearchableStudies
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 13 Oct 2015 17:48:30 +0200
parents 275780da54ae
children 5ebd6cbb3da8
files CMakeLists.txt OrthancServer/DatabaseWrapper.cpp OrthancServer/DatabaseWrapper.h OrthancServer/DatabaseWrapperBase.cpp OrthancServer/DatabaseWrapperBase.h OrthancServer/IDatabaseWrapper.h OrthancServer/PrepareDatabase.sql OrthancServer/ServerIndex.cpp OrthancServer/ServerToolbox.cpp OrthancServer/ServerToolbox.h OrthancServer/Upgrade5To6.sql Plugins/Engine/OrthancPluginDatabase.cpp Plugins/Engine/OrthancPluginDatabase.h
diffstat 13 files changed, 145 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Tue Oct 13 16:57:55 2015 +0200
+++ b/CMakeLists.txt	Tue Oct 13 17:48:30 2015 +0200
@@ -240,6 +240,7 @@
   PREPARE_DATABASE            ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/PrepareDatabase.sql
   UPGRADE_DATABASE_3_TO_4     ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade3To4.sql
   UPGRADE_DATABASE_4_TO_5     ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade4To5.sql
+  UPGRADE_DATABASE_5_TO_6     ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade5To6.sql
   CONFIGURATION_SAMPLE        ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Configuration.json
   DICOM_CONFORMANCE_STATEMENT ${CMAKE_CURRENT_SOURCE_DIR}/Resources/DicomConformanceStatement.txt
   LUA_TOOLBOX                 ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Toolbox.lua
--- a/OrthancServer/DatabaseWrapper.cpp	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/DatabaseWrapper.cpp	Tue Oct 13 17:48:30 2015 +0200
@@ -359,11 +359,13 @@
     if (version_ == 5)
     {
       LOG(WARNING) << "Upgrading database version from 5 to 6";
-      // No change in the DB schema, the step from version 5 to 6 only
-      // consists in reconstructing the main DICOM tags information.
       db_.BeginTransaction();
+      ExecuteUpgradeScript(db_, EmbeddedResources::UPGRADE_DATABASE_5_TO_6);      
+      // Reconstruct the main DICOM tags information.
+      Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Patient);
       Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Study);
       Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Series);
+      Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Instance);
       db_.CommitTransaction();
       version_ = 6;
     }    
@@ -484,5 +486,4 @@
       target[key] = s.ColumnString(1);
     }
   }
-
 }
--- a/OrthancServer/DatabaseWrapper.h	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/DatabaseWrapper.h	Tue Oct 13 17:48:30 2015 +0200
@@ -329,6 +329,11 @@
     virtual void Upgrade(unsigned int targetVersion,
                          IStorageArea& storageArea);
 
+    virtual void StoreStudyModule(int64_t id,
+                                  const DicomMap& module)
+    {
+      base_.StoreStudyModule(id, module);
+    }
 
 
     /**
--- a/OrthancServer/DatabaseWrapperBase.cpp	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/DatabaseWrapperBase.cpp	Tue Oct 13 17:48:30 2015 +0200
@@ -33,6 +33,8 @@
 #include "PrecompiledHeadersServer.h"
 #include "DatabaseWrapperBase.h"
 
+#include "../Core/DicomFormat/DicomArray.h"
+
 #include <stdio.h>
 
 namespace Orthanc
@@ -309,6 +311,13 @@
       s.BindInt64(0, id);
       s.Run();
     }
+
+    // New in DB v6 (Orthanc >= 0.9.5)
+    {
+      SQLite::Statement s(db_, SQLITE_FROM_HERE, "DELETE FROM SearchableStudies WHERE id=?");
+      s.BindInt64(0, id);
+      s.Run();
+    }
   }
 
 
@@ -712,4 +721,27 @@
       target.push_back(s.ColumnInt64(0));
     }
   }
+
+
+  void DatabaseWrapperBase::StoreStudyModule(int64_t id,
+                                             const DicomMap& module)
+  {
+    DicomArray a(module);
+
+    for (size_t i = 0; i < a.GetSize(); i++)
+    {
+      const DicomTag& tag = a.GetElement(i).GetTag();
+      const DicomValue& value = a.GetElement(i).GetValue();
+
+      if (!value.IsNull())
+      {
+        SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO SearchableStudies VALUES(?, ?, ?, ?)");
+        s.BindInt64(0, id);
+        s.BindInt(1, tag.GetGroup());
+        s.BindInt(2, tag.GetElement());
+        s.BindString(3, value.AsString());
+        s.Run();
+      }
+    }
+  }
 }
--- a/OrthancServer/DatabaseWrapperBase.h	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/DatabaseWrapperBase.h	Tue Oct 13 17:48:30 2015 +0200
@@ -42,6 +42,7 @@
 #include "ServerEnumerations.h"
 
 #include <list>
+#include <boost/noncopyable.hpp>
 
 
 namespace Orthanc
@@ -51,7 +52,7 @@
    * database plugin whose code is in
    * "../Plugins/Samples/DatabasePlugin".
    **/
-  class DatabaseWrapperBase
+  class DatabaseWrapperBase : public boost::noncopyable
   {
   private:
     SQLite::Connection&  db_;
@@ -192,6 +193,9 @@
 
     void LookupIdentifier(std::list<int64_t>& target,
                           const std::string& value);
+
+    void StoreStudyModule(int64_t id,
+                          const DicomMap& module);
   };
 }
 
--- a/OrthancServer/IDatabaseWrapper.h	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/IDatabaseWrapper.h	Tue Oct 13 17:48:30 2015 +0200
@@ -193,5 +193,8 @@
 
     virtual void Upgrade(unsigned int targetVersion,
                          IStorageArea& storageArea) = 0;
+
+    virtual void StoreStudyModule(int64_t id,
+                                  const DicomMap& module) = 0;
   };
 }
--- a/OrthancServer/PrepareDatabase.sql	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/PrepareDatabase.sql	Tue Oct 13 17:48:30 2015 +0200
@@ -27,6 +27,15 @@
        PRIMARY KEY(id, tagGroup, tagElement)
        );
 
+-- The following table was added in Orthanc 0.9.5 (database v6)
+CREATE TABLE SearchableStudies(
+       id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE,
+       tagGroup INTEGER,
+       tagElement INTEGER,
+       value TEXT,  -- assumed to be in upper case
+       PRIMARY KEY(id, tagGroup, tagElement)
+       );
+
 CREATE TABLE Metadata(
        id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE,
        type INTEGER,
@@ -86,6 +95,10 @@
 CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement);
 CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY);
 
+-- The 2 following indexes were added in Orthanc 0.9.5 (database v6)
+CREATE INDEX SearchableStudiesIndex1 ON SearchableStudies(id);
+CREATE INDEX SearchableStudiesIndexValues ON SearchableStudies(value COLLATE BINARY);
+
 CREATE INDEX ChangesIndex ON Changes(internalId);
 
 CREATE TRIGGER AttachedFileDeleted
--- a/OrthancServer/ServerIndex.cpp	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/ServerIndex.cpp	Tue Oct 13 17:48:30 2015 +0200
@@ -687,7 +687,14 @@
       {
         study = CreateResource(hasher.HashStudy(), ResourceType_Study);
         Toolbox::SetMainDicomTags(db_, study, ResourceType_Study, dicomSummary, true);
-        Toolbox::SetMainDicomTags(db_, study, ResourceType_Patient, dicomSummary, false);  // New in version 0.9.5 (db v6)
+
+        // New in version 0.9.5 (db v6)
+        Toolbox::SetMainDicomTags(db_, study, ResourceType_Patient, dicomSummary, false);
+
+        DicomMap module;
+        Toolbox::ExtractModule(module, dicomSummary, DicomModule_Patient, true  /* normalize */);
+        Toolbox::ExtractModule(module, dicomSummary, DicomModule_Study, true  /* normalize */);
+        db_.StoreStudyModule(study, module);
       }
 
       // Create the patient if needed
--- a/OrthancServer/ServerToolbox.cpp	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/ServerToolbox.cpp	Tue Oct 13 17:48:30 2015 +0200
@@ -307,11 +307,19 @@
             break;
 
           case ResourceType_Study:
+          {
             Toolbox::SetMainDicomTags(database, resource, ResourceType_Study, dicomSummary, true);
 
             // Duplicate the patient tags at the study level (new in Orthanc 0.9.5 - db v6)
             Toolbox::SetMainDicomTags(database, resource, ResourceType_Patient, dicomSummary, false);
+
+            DicomMap module;
+            Toolbox::ExtractModule(module, dicomSummary, DicomModule_Patient, true  /* normalize */);
+            Toolbox::ExtractModule(module, dicomSummary, DicomModule_Study, true  /* normalize */);
+            database.StoreStudyModule(resource, module);
+
             break;
+          }
 
           case ResourceType_Series:
             Toolbox::SetMainDicomTags(database, resource, ResourceType_Series, dicomSummary, true);
@@ -326,5 +334,34 @@
         }
       }
     }
+
+
+    void ExtractModule(DicomMap& result,   // WARNING: Will not be cleared!
+                       const DicomMap& summary,
+                       DicomModule module,
+                       bool normalize)
+    {
+      typedef std::set<DicomTag> ModuleTags;
+      ModuleTags moduleTags;
+      DicomTag::AddTagsForModule(moduleTags, module);
+
+      for (ModuleTags::const_iterator tag = moduleTags.begin(); tag != moduleTags.end(); ++tag)
+      {
+        const DicomValue* value = summary.TestAndGetValue(*tag);
+        if (value != NULL &&
+            !value->IsNull())
+        {
+          std::string t = value->AsString();
+
+          if (normalize)
+          {
+            t = StripSpaces(ConvertToAscii(t));
+            ToUpperCase(t);
+          }
+
+          result.SetValue(*tag, t);
+        }      
+      }
+    }
   }
 }
--- a/OrthancServer/ServerToolbox.h	Tue Oct 13 16:57:55 2015 +0200
+++ b/OrthancServer/ServerToolbox.h	Tue Oct 13 17:48:30 2015 +0200
@@ -60,5 +60,10 @@
     void ReconstructMainDicomTags(IDatabaseWrapper& database,
                                   IStorageArea& storageArea,
                                   ResourceType level);
+
+    void ExtractModule(DicomMap& result,   // WARNING: Will not be cleared!
+                       const DicomMap& summary,
+                       DicomModule module,
+                       bool normalize);
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Upgrade5To6.sql	Tue Oct 13 17:48:30 2015 +0200
@@ -0,0 +1,21 @@
+-- This SQLite script updates the version of the Orthanc database from 5 to 6.
+
+
+-- Add a new table to enable full-text indexed search over studies
+
+CREATE TABLE SearchableStudies(
+       id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE,
+       tagGroup INTEGER,
+       tagElement INTEGER,
+       value TEXT,  -- assumed to be in upper case
+       PRIMARY KEY(id, tagGroup, tagElement)
+       );
+
+CREATE INDEX SearchableStudiesIndex1 ON SearchableStudies(id);
+CREATE INDEX SearchableStudiesIndexValues ON SearchableStudies(value COLLATE BINARY);
+
+
+-- Change the database version
+-- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration
+
+UPDATE GlobalProperties SET value="6" WHERE property=1;
--- a/Plugins/Engine/OrthancPluginDatabase.cpp	Tue Oct 13 16:57:55 2015 +0200
+++ b/Plugins/Engine/OrthancPluginDatabase.cpp	Tue Oct 13 17:48:30 2015 +0200
@@ -869,6 +869,14 @@
   }
 
 
+  void OrthancPluginDatabase::StoreStudyModule(int64_t id,
+                                               const DicomMap& module)
+  {
+    // TODO
+    throw OrthancException(ErrorCode_NotImplemented);
+  }
+
+
   void OrthancPluginDatabase::AnswerReceived(const _OrthancPluginDatabaseAnswer& answer)
   {
     if (answer.type == _OrthancPluginDatabaseAnswerType_None)
--- a/Plugins/Engine/OrthancPluginDatabase.h	Tue Oct 13 16:57:55 2015 +0200
+++ b/Plugins/Engine/OrthancPluginDatabase.h	Tue Oct 13 17:48:30 2015 +0200
@@ -254,6 +254,9 @@
     virtual void Upgrade(unsigned int targetVersion,
                          IStorageArea& storageArea);
 
+    virtual void StoreStudyModule(int64_t id,
+                                  const DicomMap& module);
+
     void AnswerReceived(const _OrthancPluginDatabaseAnswer& answer);
   };
 }