diff OrthancServer/SQLiteDatabaseWrapper.cpp @ 3030:25afa7b8cb51 db-changes

SQLiteDatabaseWrapper::ApplyLookupResources()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 19 Dec 2018 11:18:39 +0100
parents ea653ec47f31
children 18a2d196414b
line wrap: on
line diff
--- a/OrthancServer/SQLiteDatabaseWrapper.cpp	Tue Dec 18 18:56:55 2018 +0100
+++ b/OrthancServer/SQLiteDatabaseWrapper.cpp	Wed Dec 19 11:18:39 2018 +0100
@@ -1206,6 +1206,28 @@
   }
 
 
+  static std::string FormatLevel(ResourceType level)
+  {
+    switch (level)
+    {
+      case ResourceType_Patient:
+        return "patients";
+        
+      case ResourceType_Study:
+        return "studies";
+        
+      case ResourceType_Series:
+        return "series";
+        
+      case ResourceType_Instance:
+        return "instances";
+
+      default:
+        throw OrthancException(ErrorCode_InternalError);
+    }
+  }      
+  
+
   static void FormatJoin(std::string& target,
                          const DatabaseConstraint& constraint,
                          size_t index)
@@ -1230,31 +1252,8 @@
       target += "MainDicomTags ";
     }
 
-    target += tag + " ON " + tag + ".id = ";
-
-    switch (constraint.GetLevel())
-    {
-      case ResourceType_Patient:
-        target += "patient";
-        break;
-        
-      case ResourceType_Study:
-        target += "study";
-        break;
-        
-      case ResourceType_Series:
-        target += "series";
-        break;
-        
-      case ResourceType_Instance:
-        target += "instance";
-        break;
-
-      default:
-        throw OrthancException(ErrorCode_InternalError);
-    }
-    
-    target += (".internalId AND " + tag + ".tagGroup = " +
+    target += (tag + " ON " + tag + ".id = " + FormatLevel(constraint.GetLevel()) +
+               ".internalId AND " + tag + ".tagGroup = " +
                boost::lexical_cast<std::string>(constraint.GetTag().GetGroup()) +
                " AND " + tag + ".tagElement = " +
                boost::lexical_cast<std::string>(constraint.GetTag().GetElement()));
@@ -1391,7 +1390,7 @@
       }
 
       default:
-        // Don't modify "parameters"!
+        // Don't modify "parameters" in this case!
         return false;
     }
 
@@ -1406,23 +1405,94 @@
 
     return true;
   }
-  
-  
-  void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId,
-                                                  std::vector<std::string>& instancesId,
-                                                  const std::vector<DatabaseConstraint>& lookup,
-                                                  size_t limit)
+
+
+  static void PrepareLookup(SQLite::Connection& db)
+  {
+    SQLite::Statement s(db, SQLITE_FROM_HERE, "DROP TABLE IF EXISTS Lookup");
+    s.Run();
+  }
+
+
+  static void AnswerLookup(std::vector<std::string>& resourcesId,
+                           std::vector<std::string>& instancesId,
+                           SQLite::Connection& db,
+                           ResourceType level)
   {
-    printf("ICI 1\n");
+    resourcesId.clear();
+    instancesId.clear();
+    
+    std::auto_ptr<SQLite::Statement> statement;
+    
+    switch (level)
+    {
+      case ResourceType_Patient:
+      {
+        statement.reset(
+          new SQLite::Statement(
+            db, SQLITE_FROM_HERE,
+            "SELECT patients.publicId, instances.publicID FROM Lookup AS patients "
+            "INNER JOIN Resources studies ON patients.internalId=studies.parentId "
+            "INNER JOIN Resources series ON studies.internalId=series.parentId "
+            "INNER JOIN Resources instances ON series.internalId=instances.parentId "
+            "GROUP BY patients.publicId"));
+      
+        break;
+      }
 
-    {
-      SQLite::Statement s(db_, "DROP TABLE IF EXISTS Lookup");
-      s.Run();
+      case ResourceType_Study:
+      {
+        statement.reset(
+          new SQLite::Statement(
+            db, SQLITE_FROM_HERE,
+            "SELECT studies.publicId, instances.publicID FROM Lookup AS studies "
+            "INNER JOIN Resources series ON studies.internalId=series.parentId "
+            "INNER JOIN Resources instances ON series.internalId=instances.parentId "
+            "GROUP BY studies.publicId"));
+      
+        break;
+      }
+
+      case ResourceType_Series:
+      {
+        statement.reset(
+          new SQLite::Statement(
+            db, SQLITE_FROM_HERE,
+            "SELECT series.publicId, instances.publicID FROM Lookup AS series "
+            "INNER JOIN Resources instances ON series.internalId=instances.parentId "
+            "GROUP BY series.publicId"));
+      
+        break;
+      }
+
+      case ResourceType_Instance:
+      {
+        statement.reset(
+          new SQLite::Statement(
+            db, SQLITE_FROM_HERE, "SELECT publicId, publicId FROM Lookup"));
+        
+        break;
+      }
+      
+      default:
+        throw OrthancException(ErrorCode_InternalError);
     }
-    
-    std::string joins, comparisons;
-    std::vector<std::string> parameters;
 
+    assert(statement.get() != NULL);
+      
+    while (statement->Step())
+    {
+      resourcesId.push_back(statement->ColumnString(0));
+      instancesId.push_back(statement->ColumnString(1));
+    }
+  }
+
+
+  static void FormatConstraints(std::string& joins,
+                                std::string& comparisons,
+                                std::vector<std::string>& parameters,
+                                const std::vector<DatabaseConstraint>& lookup)
+  {
     size_t count = 0;
     
     for (size_t i = 0; i < lookup.size(); i++)
@@ -1440,11 +1510,25 @@
         count ++;
       }
     }
+  }
+                                
+  
+  
+  void SQLiteDatabaseWrapper::ApplyLookupPatients(std::vector<std::string>& patientsId,
+                                                  std::vector<std::string>& instancesId,
+                                                  const std::vector<DatabaseConstraint>& lookup,
+                                                  size_t limit)
+  {
+    PrepareLookup(db_);
+    
+    std::string joins, comparisons;
+    std::vector<std::string> parameters;
+    FormatConstraints(joins, comparisons, parameters, lookup);
 
     {
       std::string sql = ("CREATE TEMPORARY TABLE Lookup AS "
-                         "SELECT patient.publicId, patient.internalId FROM Resources AS patient" +
-                         joins + " WHERE patient.resourceType = " +
+                         "SELECT patients.publicId, patients.internalId FROM Resources AS patients" +
+                         joins + " WHERE patients.resourceType = " +
                          boost::lexical_cast<std::string>(ResourceType_Patient) + comparisons);
 
       if (limit != 0)
@@ -1458,6 +1542,88 @@
 
       for (size_t i = 0; i < parameters.size(); i++)
       {
+        s.BindString(i, parameters[i]);
+      }
+
+      s.Run();
+    }
+
+    AnswerLookup(patientsId, instancesId, db_, ResourceType_Patient);
+  }
+
+
+  void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId,
+                                                   std::vector<std::string>& instancesId,
+                                                   const std::vector<DatabaseConstraint>& lookup,
+                                                   ResourceType queryLevel,
+                                                   size_t limit)
+  {
+    assert(ResourceType_Patient < ResourceType_Study &&
+           ResourceType_Study < ResourceType_Series &&
+           ResourceType_Series < ResourceType_Instance);
+    
+    ResourceType upperLevel = queryLevel;
+    ResourceType lowerLevel = queryLevel;
+
+    for (size_t i = 0; i < lookup.size(); i++)
+    {
+      ResourceType level = lookup[i].GetLevel();
+
+      if (level < upperLevel)
+      {
+        upperLevel = level;
+      }
+
+      if (level > lowerLevel)
+      {
+        lowerLevel = level;
+      }
+    }
+    
+    printf("ICI 2: [%s] -> [%s]\n", EnumerationToString(upperLevel), EnumerationToString(lowerLevel));
+    
+    PrepareLookup(db_);
+    
+    std::string joins, comparisons;
+    std::vector<std::string> parameters;
+    FormatConstraints(joins, comparisons, parameters, lookup);
+
+    {
+      std::string sql = ("CREATE TEMPORARY TABLE Lookup AS SELECT " +
+                         FormatLevel(queryLevel) + ".publicId, " +
+                         FormatLevel(queryLevel) + ".internalId" +
+                         " FROM Resources AS " + FormatLevel(queryLevel));
+
+      for (int level = queryLevel - 1; level >= upperLevel; level--)
+      {
+        sql += (" INNER JOIN Resources " +
+                FormatLevel(static_cast<ResourceType>(level)) + " ON " +
+                FormatLevel(static_cast<ResourceType>(level)) + ".internalId=" +
+                FormatLevel(static_cast<ResourceType>(level + 1)) + ".parentId");
+      }
+      
+      for (int level = queryLevel + 1; level <= lowerLevel; level++)
+      {
+        sql += (" INNER JOIN Resources " +
+                FormatLevel(static_cast<ResourceType>(level - 1)) + " ON " +
+                FormatLevel(static_cast<ResourceType>(level - 1)) + ".internalId=" +
+                FormatLevel(static_cast<ResourceType>(level)) + ".parentId");
+      }
+      
+      sql += (joins + " WHERE " + FormatLevel(queryLevel) + ".resourceType = " +
+              boost::lexical_cast<std::string>(queryLevel) + comparisons);
+
+      if (limit != 0)
+      {
+        sql += " LIMIT " + boost::lexical_cast<std::string>(limit);
+      }
+
+      printf("[%s]\n", sql.c_str());
+
+      SQLite::Statement s(db_, sql);
+
+      for (size_t i = 0; i < parameters.size(); i++)
+      {
         printf("   %lu = '%s'\n", i, parameters[i].c_str());
         s.BindString(i, parameters[i]);
       }
@@ -1465,52 +1631,6 @@
       s.Run();
     }
 
-    {
-      SQLite::Statement s
-        (db_, "SELECT patient.publicId, instances.publicID FROM Lookup AS patient "
-         "INNER JOIN Resources studies ON patient.internalId=studies.parentId "
-         "INNER JOIN Resources series ON studies.internalId=series.parentId "
-         "INNER JOIN Resources instances ON series.internalId=instances.parentId "
-         "GROUP BY patient.publicId");
-      
-      patientsId.clear();
-
-      while (s.Step())
-      {
-        const std::string patient = s.ColumnString(0);
-        const std::string instance = s.ColumnString(1);
-        patientsId.push_back(patient);
-        instancesId.push_back(instance);
-        printf("** [%s] [%s]\n", patient.c_str(), instance.c_str());
-      }
-    }
-  }
-  
-
-  void SQLiteDatabaseWrapper::ApplyLookupResources(std::vector<std::string>& resourcesId,
-                                                   std::vector<std::string>& instancesId,
-                                                   const std::vector<DatabaseConstraint>& lookup,
-                                                   ResourceType queryLevel,
-                                                   size_t limit)
-  {
-    ResourceType upperLevel = queryLevel;
-    ResourceType lowerLevel = queryLevel;
-
-    for (size_t i = 0; i < lookup.size(); i++)
-    {
-      if (!IsResourceLevelAboveOrEqual(upperLevel, lookup[i].GetLevel()))
-      {
-        upperLevel = lookup[i].GetLevel();
-      }
-
-      if (!IsResourceLevelAboveOrEqual(lookup[i].GetLevel(), lowerLevel))
-      {
-        lowerLevel = lookup[i].GetLevel();
-      }
-    }
-    
-    printf("ICI 2: [%s] -> [%s]\n", EnumerationToString(upperLevel), EnumerationToString(lowerLevel));
-    
-    throw OrthancException(ErrorCode_NotImplemented);
+    AnswerLookup(resourcesId, instancesId, db_, queryLevel);
   }
 }