-
Notifications
You must be signed in to change notification settings - Fork 0
This is a simplified documentation of the c++ API. Start a new project by using the template CMakeFile.txt (TODO).
Two sections here: first the core functions common to all types (schema) of database, and the standard functions specific to the standard database. Those classes and functions (should) works for any type of databases derivated from the StandardDatabase
.
In the following code, we omit the syd
namespace, we use:
using namespace syd;
Get instance:
DatabaseManager * m = DatabaseManager::GetInstance();
auto & list = m->GetDatabaseSchemas();
Create a database:
Database * db = m->Create("StandardDatabase", dbname, folder);
Read a database:
Database * db = m->Read(dbname);
StandardDatabase * db = m->Read<StandardDatabase>(dbname);
Basics operations are 'CRUD': Create, Read, Update and Delete.
// Get the name of the sql schema, i.e. "StandardDatabase"
std::string s = db->GetDatabaseSchema();
// Get the filename i.e. test.db
std::string s = db->GetFilename();
// Get the image folder of the db, relative to the test.db folder
std::string s = db->GetDatabaseRelativeFolder();
std::string s = db->GetDatabaseAbsoluteFolder();
Insert an element (with table Patient as example but could be other tables):
// For a generic database (unknown type)
auto r = db->New("Patient"); // r is shared_ptr<syd::Record>
db->Set(r, args);
db->Insert(r);
// For a standard database (or derived from)
auto r = syd::Patient::New(); // r is shared_ptr<syd::Patient> (or syd::Patient::pointer)
db->Set(p, args);
db->Insert(p);
// Get all patients
syd::Patient::vector v;
db->Query(v);
// Get all patients matching a query
typedef odb::query<Patient> QueryType;
QueryType q = (QueryType::name == "toto" and QueryType::age < 20)
db->Query(q, v);
// Get only one patient matching the query
syd::Patient::pointer patient;
db->QueryOne(patient, q);
// Get only one patient with its id
db->QueryOne(patient, id);
// Others functions
int n = db->GetNumberOfElements<syd::Patient>(); // slow
Update records in the database.
db->Update(patient);
db->Update(v);
// Delete by knowing the type of the table
db->Delete<Patient>(patient);
db->Delete<Patient>(vector_of_patients);
// Delete with the name of the table and id
db->Delete("Patient", id);
db->Delete("Patient", vector_of_ids);
Deleting a record can be complicated due to foreign keys (FK) in some tables. Two mecanisms are provided:
- On cascade delete. When a table has a FK, it is possible to choose to delete the record if the record corresponding to the FK is deleted. This is done with the following pragma :
#pragma db on_delete(cascade)
. See table Injection in standard database for example. - In other circumstance, additional tasks must be performed when a record is deleted (for example removing the file on disk when an image is deleted). This is done with the following virtual function:
virtual void OnDelete(const std::string & table_name, TableElementBase * e);
This callback is called every time a record (e) from the table table_name is deleted. See StandardDatabase for example.
Every access to a database can fail for one reason, you can test the result with a try/catch. See here:
try {
// Here, access to the database (insert, query etc)
}
catch (const Exception & e) {
std::cout << e->what(); // Go here if something wrong
}
For debug, you can access to the last SQL query with:
std::string s = db->GetLastSQLQuery();
List of tables: TODO
Convenient functions for common queries (to retrieve a patient from his name for example):
// Let db be a syd::Database
Patient patient;
FindPatientByNameOrStudyId(patient, db, "toto");
std::vector<Tag> tags;
std::string tag_names; // separated by space
FindTags(tags, db, tag_names);
When records are delete, a mecanism takes care about dependencies.
Policy:
- Image: also delete Files.
- Files: also delete the files on disk, the Image and the DicomFile
- DicomFile: also delete the File, the DicomSerie
- DicomSerie: also delete the DicomFiles
- Injection: also delete DicomSeries and Timepoint
- Radionuclide: also delete the Injection
- Patient: also delete the Injection
- Tag : TODO
- Timepoint: TODO
Create an object DicomSerieBuilder and set the basics informations:
DicomSerieBuilder b(db);
b.SetInjection(injection);
b.SetForcePatientFlag(true);
b.SearchForFilesInFolder(folder, files);
Main function to create a DicomSerie from a file. Checks if the file is not already in the db, guess if the file should be added to an existing DicomSerie or if a new DicomSerie. The DicomSerie is not yet inserted into the db. See next function.
for(auto f:files) b.CreateDicomSerieFromFile(f.c_str());
Once the files have been created (previous function), insert all created series in the db.
b.InsertDicomSeries();
The class ImageBuilder allow to to create record in the Image table and the associated mhd/raw files.
Convert a dicom image to a mhd (and insert an Image)
ImageBuilder b(db);
syd::Image image = builder.InsertImage(d);
Create and insert a ROI as a binary mask: RoiMaskImage. Need a filename (mhd) and a DicomSerie to be linked with.
ImageBuilder b(db);
syd::Image image = b.InsertRoiMaskImage(dicom, roitype, filename);
It is also possible to create an image by stitching two dicom together:
ImageBuilder b(db);
syd::Image image = builder.InsertStitchedImage(tag, dicom1, dicom2);
It is recommended to add tag to images:
Tag t; // get a tag somehow
image.AddTag(t);
db->Update(image);
Create an object TimepointBuilder and set the basics informations:
TimepointBuilder b(db);
b.SetTag(tag);
b.SetIntraTimepointMaxHourDiff(1); // 1 hour max difference between
Consider some DicomSerie and create the corresponding Timepoints. Guess that two dicoms with more than 1 hour acquisition time difference are not in the same Timepoint.
for(auto d:dicom_series) b.InsertDicomSerie(d);
Other functions:
GuessState s = b.GuessTimepointForThisDicomSerie(dicom_serie, vector_of_timepoints);
GuessState s = b.GuessIfDicomCanBeInThisTimepoint(dicom_serie, timepoint);
timepoint = b.CreateTimepoint(dicom_serie);
b.AddDicom(timepoint, dicom_serie);