Skip to content
David Sarrut edited this page Jul 6, 2015 · 23 revisions

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.

Core

In the following code, we omit the syd namespace, we use:

    using namespace syd;

Database manager

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);

Functions common to all databases (CRUD)

Basics operations are 'CRUD': Create, Read, Update and Delete.

Get information:

    // 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();

Create

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 = db->New<syd::Patient>(); // r is shared_ptr<syd::Patient>
    or
    syd::Patient::pointer p;
    db->New(p);
    db->Set(p, args);
    db->Insert(p);

Query:

    // Get all patients
    db->Query<Patient>(vector_of_patients);

    // Get all patients matching a query
    typedef odb::query<Patient> QueryType;
    QueryType q = (QueryType::name == "toto" and QueryType::age < 20)
    db->Query<Patient>(q, vector_of_patients);

    // Get only one patient matching the query
    patient = db->QueryOne(q);

    // Get only one patient with its id
    patient = db->QueryOne(id);

    // Others functions
    int n = db->Count(q);
    if (db->IfExist<Patient>(id)) { ... }

Update:

Update a record in the database.

    db->Update<Patient>(patient);
    db->Update<Patient>(vector_of_patients);

Delete:

    // 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.

Exceptions

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();

Standard Database

List of tables: TODO

Some functions related to tables

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);

Records deletion

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

DicomSerieBuilder

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();

ImageBuilder

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);

TimepointBuilder

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);
Clone this wiki locally