diff Framework/Plugins/IndexBackend.cpp @ 70:e6c13ddd26d9 db-changes

all integration tests passing with LookupResources extension
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 03 Jan 2019 14:04:46 +0100
parents 19764fc60ade
children a4e440e65c68
line wrap: on
line diff
--- a/Framework/Plugins/IndexBackend.cpp	Thu Jan 03 10:07:27 2019 +0100
+++ b/Framework/Plugins/IndexBackend.cpp	Thu Jan 03 14:04:46 2019 +0100
@@ -56,7 +56,7 @@
   }
 
   
-  int64_t IndexBackend::ReadInteger64(const DatabaseManager::CachedStatement& statement,
+  int64_t IndexBackend::ReadInteger64(const DatabaseManager::StatementBase& statement,
                                       size_t field)
   {
     if (statement.IsDone())
@@ -78,7 +78,7 @@
   }
 
 
-  int32_t IndexBackend::ReadInteger32(const DatabaseManager::CachedStatement& statement,
+  int32_t IndexBackend::ReadInteger32(const DatabaseManager::StatementBase& statement,
                                       size_t field)
   {
     if (statement.IsDone())
@@ -100,11 +100,11 @@
   }
 
     
-  std::string IndexBackend::ReadString(const DatabaseManager::CachedStatement& statement,
+  std::string IndexBackend::ReadString(const DatabaseManager::StatementBase& statement,
                                        size_t field)
   {
     const IValue& value = statement.GetResultField(field);
-      
+
     switch (value.GetType())
     {
       case ValueType_BinaryString:
@@ -1586,31 +1586,67 @@
   class IndexBackend::LookupFormatter : public Orthanc::ISqlLookupFormatter
   {
   private:
-    Dialect  dialect_;
+    Dialect     dialect_;
+    size_t      count_;
+    Dictionary  dictionary_;
 
+    static std::string FormatParameter(size_t index)
+    {
+      return "p" + boost::lexical_cast<std::string>(index);
+    }
+    
   public:
-    LookupFormatter(Dialect  dialect) :
-      dialect_(dialect)
+    LookupFormatter(Dialect dialect) :
+      dialect_(dialect),
+      count_(0)
     {
     }
 
     virtual std::string GenerateParameter(const std::string& value)
     {
+      const std::string key = FormatParameter(count_);
+
+      count_ ++;
+      dictionary_.SetUtf8Value(key, value);
+
+      return "${" + key + "}";
+    }
+
+    virtual std::string FormatResourceType(Orthanc::ResourceType level)
+    {
+      return boost::lexical_cast<std::string>(Orthanc::Plugins::Convert(level));
+    }
+
+    virtual std::string FormatWildcardEscape()
+    {
       switch (dialect_)
       {
-        case Dialect_MySQL:
-          break;
-        
+        case Dialect_SQLite:
         case Dialect_PostgreSQL:
-          break;
+          return "ESCAPE '\\'";
 
-        case Dialect_SQLite:
-          break;
+        case Dialect_MySQL:
+          return "ESCAPE '\\\\'";
 
         default:
           throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
       }
     }
+
+    void PrepareStatement(DatabaseManager::StandaloneStatement& statement) const
+    {
+      statement.SetReadOnly(true);
+      
+      for (size_t i = 0; i < count_; i++)
+      {
+        statement.SetParameterType(FormatParameter(i), ValueType_Utf8String);
+      }
+    }
+
+    const Dictionary& GetDictionary() const
+    {
+      return dictionary_;
+    }
   };
 #endif
 
@@ -1622,13 +1658,65 @@
                                      uint32_t limit,
                                      bool requestSomeInstance)
   {
+    LookupFormatter formatter(manager_.GetDialect());
+
     std::string sql;
+    Orthanc::ISqlLookupFormatter::Apply(sql, formatter, lookup,
+                                        Orthanc::Plugins::Convert(queryLevel), limit);
 
+    if (requestSomeInstance)
     {
-      LookupFormatter formatter(manager_.GetDialect());
-      Orthanc::ISqlLookupFormatter::Apply(sql, formatter, lookup,
-                                          Orthanc::Plugins::Convert(queryLevel), limit);
+      // Composite query to find some instance if requested
+      switch (queryLevel)
+      {
+        case OrthancPluginResourceType_Patient:
+          sql = ("SELECT patients.publicId, MIN(instances.publicId) FROM (" + sql + ") patients "
+                 "INNER JOIN Resources studies   ON studies.parentId   = patients.internalId "
+                 "INNER JOIN Resources series    ON series.parentId    = studies.internalId "
+                 "INNER JOIN Resources instances ON instances.parentId = series.internalId "
+                 "GROUP BY patients.publicId");
+          break;
+
+        case OrthancPluginResourceType_Study:
+          sql = ("SELECT studies.publicId, MIN(instances.publicId) FROM (" + sql + ") studies "
+                 "INNER JOIN Resources series    ON series.parentId    = studies.internalId "
+                 "INNER JOIN Resources instances ON instances.parentId = series.internalId "
+                 "GROUP BY studies.publicId");                 
+          break;
+
+        case OrthancPluginResourceType_Series:
+          sql = ("SELECT series.publicId, MIN(instances.publicId) FROM (" + sql + ") series "
+                 "INNER JOIN Resources instances ON instances.parentId = series.internalId "
+                 "GROUP BY series.publicId");
+          break;
+
+        case OrthancPluginResourceType_Instance:
+          sql = ("SELECT instances.publicId, instances.publicId FROM (" + sql + ") instances");
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
     }
+
+    DatabaseManager::StandaloneStatement statement(GetManager(), sql);
+    formatter.PrepareStatement(statement);
+
+    statement.Execute(formatter.GetDictionary());
+
+    while (!statement.IsDone())
+    {
+      if (requestSomeInstance)
+      {
+        GetOutput().AnswerMatchingResource(ReadString(statement, 0), ReadString(statement, 1));
+      }
+      else
+      {
+        GetOutput().AnswerMatchingResource(ReadString(statement, 0));
+      }
+
+      statement.Next();
+    }    
   }
 #endif
 }