KaliVeda
Toolkit for HIC analysis
KVSQLROOTFile.cpp
1 #include "KVSQLROOTFile.h"
2 #include "TSystem.h"
3 
5 
6 
7 
10 KVString KVSQLROOTFile::UUID_for_object(const KVString& name) const
11 {
12  // Return unique identifier used to store object with given name in ROOT file
13 
14  fObjDB->select_data("objTable", "unique_id", Form("name = \"%s\"", name.Data()));
15  KVString uuid;
16  while (fObjDB->get_next_result())
17  uuid = get_objTable()["unique_id"].get_data<KVString>();
18  return uuid;
19 }
20 
21 
22 
25 
27 {
28  // Retrieve object from file using its name
29 
30  auto it = fObjList.find(uuid.Data());// object already retrieved from file ?
31  if (it != fObjList.end()) return it->second;
32  auto t = fObjStore->Get(uuid);
33  fObjList[uuid.Data()] = t;
34  return t;
35 }
36 
37 
38 
57 
59 {
60  // Open or (re)create a combined ROOT object store & SQL database with info on the stored objects.
61  //
62  // \param[in] filepath path to file. any shell variables will be expanded.
63  // \param[in] option see TFile constructors for possible values. default="READ".
64  //
65  // This will actually open or create two files in the directory given by filepath:
66  // + `objStore.root` - ROOT file containing objects
67  // + `objInfos.sqlite` - SQLite database containing metadata for objects
68  //
69  // When first created, the SQLite database contains a table `objTable` with the
70  // following columns:
71  //
72  // obj_idx | name | class | unique_id
73  // ------- | ---- | ----- | ---------
74  // * | * | * | *
75  //
76  // The `unique_id` for each object is generated using TUUID.
77 
78  TString FP = filepath;
79  TString OPT = option;
80  OPT.ToUpper();
81 
83  if (OPT.Contains("CREATE")) {
84  // create directory using path
85  gSystem->mkdir(filepath, true); // recursive: create any missing directories in path
86  gSystem->Chmod(filepath, 0775); // make writable for group
87  }
88  FP.Append("/");
89  TString rpath = FP + "objStore.root";
90  if (OPT == "RECREATE") gSystem->Unlink(rpath);
92  fObjStore.reset(new TFile(rpath, OPT));
94  fCurrentROOTFilePath = rpath;
95 
96  TString sqlpath = FP + "objInfos.sqlite";
97  if (OPT == "RECREATE") gSystem->Unlink(sqlpath);
98  fObjDB.reset(new KVSQLite::database(sqlpath));
99  if (OPT.Contains("CREATE")) {
100  // set up object table
101  KVSQLite::table tmp("objTable");
102  tmp.add_primary_key("obj_idx");
103  tmp.add_column("name", "TEXT");
104  tmp.add_column("class", "TEXT");
105  tmp.add_column("unique_id", "TEXT");
106  fObjDB->add_table(tmp);
107  }
108  gSystem->Chmod(sqlpath, 0664); // make writable for group
109 }
110 
111 
112 
116 
118 {
119  // Manually 'delete' ROOT file in order to force writing to disk,
120  // then change access permissions to make it writable for group
121 
122  fObjStore.reset(nullptr);
124 }
125 
126 
127 
147 
148 void KVSQLROOTFile::WriteObject(const TObject* obj, const KVNameValueList& infos)
149 {
150  // Write object in ROOT file, store infos given in list
151  //
152  // @param obj pointer to object to store
153  // @param infos list of metadata associated with object
154  //
155  // If it does not already exist, this will add to the SQLite database a table `objInfos` with the following columns:
156  //
157  // info_idx | obj_idx
158  // -------- | -------
159  // * | *
160  //
161  // This table will be augmented with columns corresponding to the names of the metadata contained in infos.
162  // e.g. if infos = {{"name","john"},{"age",50}} the table will become
163  //
164  // info_idx | obj_idx | name | age
165  // -------- | ------- | ---- | ---
166  // * | * | * | *
167  //
168 
169  if (!fObjDB->has_table("objInfos")) {
170  // set up object info table if not already done
171  KVSQLite::table tmp("objInfos");
172  tmp.add_primary_key("info_idx");
173  tmp.add_foreign_key("objTable", "obj_idx");
174  fObjDB->add_table(tmp);
175  }
176  // add any missing columns to info table
177  fObjDB->add_missing_columns("objInfos", infos);
178  // get unique ID for object
179  TUUID unid;
180  TString unique_id = unid.AsString();
181  // write object in ROOT file
183  fObjStore->cd();
184  obj->Write(unique_id);
186  // store infos on object
187  // 1 - write name, class & unique id in object table
188  fObjDB->prepare_data_insertion("objTable");
189  get_objTable()["name"] = obj->GetName();
190  get_objTable()["class"] = obj->ClassName();
191  get_objTable()["unique_id"] = unique_id;
192  fObjDB->insert_data_row();
193  fObjDB->end_data_insertion();
194  // 2 - get index of object from object table
195  fObjDB->select_data("objTable", "obj_idx", Form("unique_id=\"%s\"", unique_id.Data()));
196  int obj_idx;
197  while (fObjDB->get_next_result()) obj_idx = get_objTable()["obj_idx"].get_data<int>();
198  // 3 - add infos on object in info table
199  fObjDB->prepare_data_insertion("objInfos");
200  KVNameValueList info_copy(infos);
201  info_copy.SetValue("obj_idx", obj_idx);
202  //get_objInfos()["obj_idx"]=obj_idx;
203  //for(auto& info : infos) get_objInfos()[info.GetName()]=info;
204  get_objInfos().prepare_data(info_copy);
205  fObjDB->insert_data_row();
206  fObjDB->end_data_insertion();
207 }
208 
209 
210 
213 
215 {
216  // Return pointer to object with given name
217 
219 }
220 
221 
222 
225 
227 {
228  // List the contents of the file with associated infos
229  KVString colnames = "name,class,";
230  colnames += get_objInfos().get_column_names("obj_idx info_idx");
231  colnames.Begin(",");
232  TString tabs("\t\t\t\t");
233  while (!colnames.End()) {
234  std::cout << colnames.Next() << tabs;
235  }
236  std::cout << "\n==========================================================================================\n";
237  if (fObjDB->select_data("objTable,objInfos", colnames)) {
238  while (fObjDB->get_next_result()) {
239  colnames.Begin(",");
240  while (!colnames.End()) {
241  auto colname = colnames.Next();
242  if (colname == "name" || colname == "class")
243  std::cout << get_objTable()[colname].get_data<TString>() << tabs;
244  else
245  std::cout << get_objInfos()[colname].get_data<TString>() << tabs;
246  }
247  std::cout << std::endl;
248  }
249  }
250  else {
251  Error("ls", "Problem with KVSQLite::database::select_data");
252  }
253 }
254 
255 
256 
277 
279 {
280  // Fill the list given as argument with pointers to all objects which obey the given selection.
281  //
282  // The 'where' string will be used as the `WHERE` clause of an SQLite selection.
283  //
284  // Examples:
285  //
286  //~~~~
287  //WHERE column_1 = 100;
288  //
289  //WHERE column_2 IN (1,2,3);
290  //
291  //WHERE column_3 LIKE 'An%';
292  //
293  //WHERE column_4 BETWEEN 10 AND 20;
294  //~~~~
295  //
296  // Note that string arguments should be enclosed in single quotes.
297  //
298  // The columns of both the `objTable` (`name`, `class`) and `objInfos` tables can be used in the selection.
299 
300  fObjDB->select_data("objTable,objInfos", "unique_id", where);
301  while (fObjDB->get_next_result()) {
302  auto uuid = get_objTable()["unique_id"].get_data<KVString>();
303  list->Add(get_object_with_UUID(uuid));
304  }
305 }
306 
307 
331 
332 void KVSQLROOTFile::FillListOfObjectsWithSelection(KVSeqCollection* list, const KVString& where, const KVString& numberlist_column, int value)
333 {
334  // Fill the list given as argument with pointers to all objects which obey the given selection.
335  // 'numberlist_column' is the name of a column in the `objInfos` table containing strings which may be
336  // interpreted as KVNumberList objects. Only the entries with a number list containing 'value'
337  // will be selected.
338  //
339  // The 'where' string will be used as the `WHERE` clause of an SQLite selection.
340  //
341  // Examples:
342  //
343  //~~~~
344  //WHERE column_1 = 100;
345  //
346  //WHERE column_2 IN (1,2,3);
347  //
348  //WHERE column_3 LIKE 'An%';
349  //
350  //WHERE column_4 BETWEEN 10 AND 20;
351  //~~~~
352  //
353  // Note that string arguments should be enclosed in single quotes.
354  //
355  // The columns of both the `objTable` (`name`, `class`) and `objInfos` tables can be used in the selection.
356 
357  fObjDB->select_data("objTable,objInfos", Form("unique_id,%s", numberlist_column.Data()), where);
358  while (fObjDB->get_next_result()) {
359  KVNumberList nl(get_objInfos()[numberlist_column].get_data<KVString>());
360  if (nl.Contains(value)) {
361  auto uuid = get_objTable()["unique_id"].get_data<KVString>();
362  list->Add(get_object_with_UUID(uuid));
363  }
364  }
365 }
366 
367 
#define OPT
const char Option_t
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
void SetValue(const Char_t *name, value_type value)
Strings used to represent a set of ranges of values.
Definition: KVNumberList.h:85
Bool_t Contains(Int_t val) const
returns kTRUE if the value 'val' is contained in the ranges defined by the number list
Combine ROOT file containing objects with SQLite database with info on the objects.
Definition: KVSQLROOTFile.h:76
void WriteObject(const TObject *, const KVNameValueList &)
void FillListOfObjectsWithSelection(KVSeqCollection *list, const KVString &where)
KVSQLite::table & get_objTable() const
Definition: KVSQLROOTFile.h:90
KVSQLite::table & get_objInfos() const
Definition: KVSQLROOTFile.h:94
TObject * Get(const KVString &name) const
Return pointer to object with given name.
void ls(Option_t *="") const
List the contents of the file with associated infos.
std::unordered_map< std::string, TObject * > fObjList
for quick look-up of objects using unique id
Definition: KVSQLROOTFile.h:99
TObject * get_object_with_UUID(const KVString &name) const
Retrieve object from file using its name.
void restore_working_directory()
Definition: KVSQLROOTFile.h:85
KVString UUID_for_object(const KVString &) const
Return unique identifier used to store object with given name in ROOT file.
std::unique_ptr< TFile > fObjStore
Definition: KVSQLROOTFile.h:77
TString fCurrentROOTFilePath
full path to current ROOT file
std::unique_ptr< KVSQLite::database > fObjDB
Definition: KVSQLROOTFile.h:78
KVSQLROOTFile(const KVString &filepath, Option_t *option="READ")
void save_working_directory()
Definition: KVSQLROOTFile.h:81
Interface to ROOT SQLite database backend.
Definition: SQLiteDB.h:401
const column & add_foreign_key(const TString &other_table, const TString &other_column)
Definition: SQLiteDB.cpp:1177
const column & add_primary_key(const TString &name)
Definition: SQLiteDB.cpp:1152
column & add_column(const KVSQLite::column &c)
Definition: SQLiteDB.cpp:1115
TString get_column_names(const TString &exclude="", const TString &delim=",") const
Definition: SQLiteDB.cpp:1282
void prepare_data(const KVNameValueList &, const KVNamedParameter *=nullptr)
Definition: SQLiteDB.cpp:1244
KaliVeda extensions to ROOT collection classes.
virtual void Add(TObject *obj)
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
void Begin(TString delim) const
Definition: KVString.cpp:565
Bool_t End() const
Definition: KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
virtual const char * GetName() const
virtual const char * ClassName() const
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
virtual void Error(const char *method, const char *msgfmt,...) const
const char * Data() const
TString & Append(char c, Ssiz_t rep=1)
virtual int Chmod(const char *file, UInt_t mode)
virtual int mkdir(const char *name, Bool_t recursive=kFALSE)
virtual char * ExpandPathName(const char *path)
virtual int Unlink(const char *name)
const char * AsString() const
ClassImp(TPyArg)