Line data Source code
1 : //
2 : // DUNE DAQ modification notice:
3 : // This file has been modified from the original ATLAS oks_utils source for the DUNE DAQ project.
4 : // Fork baseline commit: c2e7dfc7 (2022-03-30).
5 : // Renamed since fork: yes (from src/bin/oks_tutorial.cpp to apps/oks_tutorial.cxx).
6 : //
7 :
8 : /************************************************************************
9 : * *
10 : * tutorial.cpp *
11 : * Explains basics of OKS C++ API including: *
12 : * - kernel initialization *
13 : * - schema design *
14 : * - data creation *
15 : * - data manipulation *
16 : * - notification *
17 : * *
18 : * Author Igor Soloviev *
19 : * *
20 : * Created: 14 Oct 1996 *
21 : * *
22 : * Modified: *
23 : * 11 Feb 1998 *
24 : * - add database quering *
25 : * *
26 : ************************************************************************/
27 :
28 : #include <boost/date_time/gregorian/gregorian.hpp>
29 :
30 : #include "oks/kernel.hpp"
31 : #include "oks/object.hpp"
32 : #include "oks/class.hpp"
33 : #include "oks/attribute.hpp"
34 : #include "oks/relationship.hpp"
35 : #include "oks/query.hpp"
36 : #include "oks/exceptions.hpp"
37 :
38 : using namespace dunedaq;
39 : using namespace dunedaq::oks;
40 :
41 : //
42 : // This function sets attribute values of class 'Person'
43 : //
44 :
45 : void
46 0 : setPersonValues(
47 : OksObject *o, // OKS object describing person
48 : const char *name, // new person name
49 : boost::gregorian::date birthday, // new person birthday
50 : const char *familySituation // new person family situation
51 : )
52 : {
53 0 : OksData d; // creates OKS data with unknown type
54 :
55 0 : d.Set(name); // sets OKS data to string 'name'
56 0 : o->SetAttributeValue("Name", &d);
57 :
58 0 : d.Set(birthday); // sets OKS data to date 'birthday'
59 0 : o->SetAttributeValue("Birthday", &d);
60 :
61 0 : d.Set(familySituation); // sets OKS data to 'familySituation'
62 0 : d.type = OksData::enum_type; // sets OKS data type to enumeration
63 0 : o->SetAttributeValue("Family_Situation", &d);
64 0 : }
65 :
66 :
67 : //
68 : // This function prints an instance of class 'Person'
69 : //
70 :
71 : void
72 0 : printPerson(
73 : const OksObject *o // OKS object describing person
74 : )
75 : {
76 0 : OksData * name(o->GetAttributeValue("Name")); // is used to store 'Name'
77 0 : OksData * birthday(o->GetAttributeValue("Birthday")); // is used to store 'Birthday'
78 0 : OksData * family(o->GetAttributeValue("Family_Situation")); // is used to store 'Family_Situation'
79 :
80 0 : std::cout << "Object " << o << " \n"
81 0 : " Name: " << *name << " \n"
82 0 : " Birthday: \'" << *birthday << "\" \n"
83 0 : " Family_Situation: " << *family << std::endl;
84 0 : }
85 :
86 :
87 : //
88 : // This function sets attribute values of class 'Employee'
89 : //
90 :
91 : void
92 0 : setEmployeeValues(
93 : OksObject *o, // OKS object that describes employee
94 : const char *name, // new employee name
95 : boost::gregorian::date birthday, // new employee birthday
96 : const char *familySituation, // new employee family situation
97 : uint32_t salary // new employee salary situation
98 : )
99 : {
100 : // we can use setPersonValues() because 'Employee' class
101 : // derived from 'Person' class
102 :
103 0 : setPersonValues(o, name, birthday, familySituation);
104 :
105 0 : OksData d(salary); // creates OKS data with ulong 'salary'
106 0 : o->SetAttributeValue("Salary", &d);
107 0 : }
108 :
109 :
110 : //
111 : // This function prints an instance of class 'Employee'
112 : //
113 :
114 : void
115 0 : printEmployee(
116 : const OksObject *o // OKS object that describes employee
117 : )
118 : {
119 : // we can use printPerson() because 'Employee' class
120 : // is derived from 'Person' class
121 :
122 0 : printPerson(o);
123 :
124 0 : OksData *department(o->GetRelationshipValue("Works at")), // is used to store 'Works at'
125 0 : *salary(o->GetAttributeValue("Salary")); // is used to store 'salary'
126 :
127 0 : std::cout << " Salary: " << *salary << " \n"
128 0 : " Works at: \"" << department->data.OBJECT->GetId() << "\"\n";
129 0 : }
130 :
131 :
132 : //
133 : // This function sets attribute values of class 'Department'
134 : //
135 :
136 : void
137 0 : setDepartmentValues(
138 : OksObject *o, // OKS object that describes department
139 : const char *name // new department name
140 : )
141 : {
142 0 : OksData d(name); // creates OKS data with string 'name'
143 :
144 0 : o->SetAttributeValue("Name", &d);
145 0 : }
146 :
147 :
148 : //
149 : // This function prints an instance of class 'Department'
150 : //
151 :
152 : void
153 0 : printDepartment(
154 : const OksObject *o // OKS object that describes department
155 : )
156 : {
157 0 : OksData *name(o->GetAttributeValue("Name")), // is used to store 'Staff'
158 0 : *staff(o->GetRelationshipValue("Staff")); // is used to store 'Name'
159 :
160 0 : std::cout << "Object " << o << "\n"
161 0 : " Name: " << *name << " \n"
162 0 : " Staff: \"" << *staff << "\"\n";
163 0 : }
164 :
165 :
166 : int
167 0 : main(int argc, char **argv)
168 : {
169 0 : const char * schema_file = "/tmp/tutorial.oks"; // default schema file
170 0 : const char * data_file = "/tmp/tutorial.okd"; // default data file
171 :
172 0 : if(
173 0 : argc > 1 &&
174 : (
175 0 : !strcmp(argv[1], "--help") ||
176 0 : !strcmp(argv[1], "-help") ||
177 0 : !strcmp(argv[1], "--h") ||
178 0 : !strcmp(argv[1], "-h")
179 : )
180 : ) {
181 0 : std::cout << "Usage: " << argv[0] << " [new_schema new_data]\n";
182 0 : return 0;
183 : }
184 :
185 0 : if(argc == 3) {
186 0 : schema_file = argv[1];
187 0 : data_file = argv[2];
188 : }
189 :
190 :
191 : // Creates OKS kernel
192 :
193 0 : std::cout << "[OKS TUTORIAL]: Creating OKS kernel...\n";
194 :
195 0 : OksKernel kernel(false, false, false, false);
196 :
197 0 : std::cout << "[OKS TUTORIAL]: Done creating OKS kernel\n\n";
198 :
199 :
200 0 : try {
201 :
202 :
203 : // Creates new schema file and tests return status
204 :
205 0 : std::cout << "[OKS TUTORIAL]: Creating new schema file...\n";
206 :
207 0 : OksFile * schema_h = kernel.new_schema(schema_file);
208 :
209 0 : std::cout << "[OKS TUTORIAL]: Done creating new schema file...\n\n"
210 : "[OKS TUTORIAL]: Define database class schema...\n\n"
211 : " ********** ************ 1..1 **************\n"
212 : " * Person *<|------* Employee *--------<>* Department *\n"
213 0 : " ********** ************ 0..N **************\n\n";
214 :
215 :
216 : // Creates class Person with three attributes "Name", "Birthday" and "Family_Situation"
217 :
218 0 : OksClass * Person = new OksClass(
219 : "Person",
220 : "It is a class to describe a person",
221 : false,
222 : &kernel
223 0 : );
224 :
225 0 : Person->add(
226 : new OksAttribute(
227 : "Name",
228 : OksAttribute::string_type,
229 : false,
230 : "",
231 : "Unknown",
232 : "A string to describe person name",
233 : true
234 0 : )
235 : );
236 :
237 0 : OksAttribute * PersonBirthday = new OksAttribute(
238 : "Birthday",
239 : OksAttribute::date_type,
240 : false,
241 : "",
242 : "2009/01/01",
243 : "A date to describe person birthday",
244 : true
245 0 : );
246 :
247 0 : Person->add(PersonBirthday);
248 :
249 0 : Person->add(
250 : new OksAttribute(
251 : "Family_Situation",
252 : OksAttribute::enum_type,
253 : false,
254 : "Single,Married,Widow(er)",
255 : "Single",
256 : "A enumeration to describe a person family state",
257 : true
258 0 : )
259 : );
260 :
261 :
262 : // Creates class Person with superclass Person, add "Salary" attribute and "Works at" relationship
263 :
264 0 : OksClass * Employee = new OksClass(
265 : "Employee",
266 : "It is a class to describe an employee",
267 : false,
268 : &kernel
269 0 : );
270 :
271 0 : OksAttribute * EmployeeSalary = new OksAttribute(
272 : "Salary",
273 : OksAttribute::u32_int_type,
274 : false,
275 : "",
276 : "1000",
277 : "An integer to describe employee salary",
278 : false
279 0 : );
280 :
281 0 : OksRelationship * WorksAt = new OksRelationship(
282 : "Works at",
283 : "Department",
284 : OksRelationship::One,
285 : OksRelationship::One,
286 : false,
287 : false,
288 : false,
289 : "A employee works at one and only one department"
290 0 : );
291 :
292 0 : Employee->add_super_class("Person");
293 0 : Employee->add(EmployeeSalary);
294 0 : Employee->add(WorksAt);
295 :
296 :
297 : // Creates class Department with one attribute and one relationship
298 :
299 0 : OksClass * Department = new OksClass(
300 : "Department",
301 : "It is a class to describe a department",
302 : false,
303 : &kernel
304 0 : );
305 :
306 0 : OksAttribute * DepartmentName = new OksAttribute(
307 : "Name",
308 : OksAttribute::string_type,
309 : false,
310 : "",
311 : "Unknown",
312 : "A string to describe department name",
313 : true
314 0 : );
315 :
316 0 : OksRelationship *DepartmentStaff = new OksRelationship(
317 : "Staff",
318 : "Employee",
319 : OksRelationship::Zero,
320 : OksRelationship::Many,
321 : true,
322 : true,
323 : true,
324 : "A department has zero or many employess"
325 0 : );
326 :
327 0 : Department->add(DepartmentName);
328 0 : Department->add(DepartmentStaff);
329 :
330 :
331 : // Saves created schema file
332 :
333 0 : std::cout << "[OKS TUTORIAL]: Saves created OKS schema file...\n";
334 :
335 0 : kernel.save_schema(schema_h);
336 :
337 :
338 : // Creates new data file and tests return status
339 :
340 0 : std::cout << "[OKS TUTORIAL]: Creating new data file...\n";
341 :
342 0 : OksFile * data_h = kernel.new_data(data_file, "OKS TUTORIAL DATA FILE");
343 :
344 0 : data_h->add_include_file(schema_file);
345 :
346 :
347 : // Creates instances of the classes
348 :
349 0 : OksObject * person1 = new OksObject(Person, "peter");
350 0 : OksObject * person2 = new OksObject(Person, "mick");
351 0 : OksObject * person3 = new OksObject(Person, "baby");
352 0 : OksObject * employee1 = new OksObject(Employee, "alexander");
353 0 : OksObject * employee2 = new OksObject(Employee, "michel");
354 0 : OksObject * employee3 = new OksObject(Employee, "maria");
355 0 : OksObject * department1 = new OksObject(Department, "IT");
356 0 : OksObject * department2 = new OksObject(Department, "EP");
357 :
358 :
359 : // Sets attribute values for instances of class 'Person'
360 :
361 0 : setPersonValues(person1, "Peter", boost::gregorian::from_string("1960/02/01"), "Married");
362 0 : setPersonValues(person2, "Mick", boost::gregorian::from_string("1956-09-01"), "Single");
363 0 : setPersonValues(person3, "Julia", boost::gregorian::from_string("2000-May-25"), "Single");
364 :
365 :
366 : // Sets attribute values for instances of class 'Employee'
367 :
368 0 : setEmployeeValues(employee1, "Alexander", boost::gregorian::from_string("1972/05/12"), "Single", 3540) ;
369 0 : setEmployeeValues(employee2, "Michel", boost::gregorian::from_string("1963/01/28"), "Married", 4950) ;
370 0 : setEmployeeValues(employee3, "Maria", boost::gregorian::from_string("1951/08/18"), "Widow(er)", 4020) ;
371 :
372 :
373 : // Sets attribute values for instance of class 'Department'
374 :
375 0 : setDepartmentValues(department1, "IT Department");
376 0 : setDepartmentValues(department2, "EP Department");
377 :
378 :
379 : // Sets relationships
380 :
381 0 : department1->AddRelationshipValue("Staff", employee1);
382 0 : department1->AddRelationshipValue("Staff", employee2);
383 0 : department2->AddRelationshipValue("Staff", employee3);
384 0 : employee1->SetRelationshipValue("Works at", department1);
385 0 : employee2->SetRelationshipValue("Works at", department1);
386 0 : employee3->SetRelationshipValue("Works at", department2);
387 :
388 :
389 : // Print out database contents
390 :
391 0 : std::cout << "\n[OKS TUTORIAL]: Database contains the following data:\n";
392 :
393 0 : printPerson(person1);
394 0 : printPerson(person2);
395 0 : printPerson(person3);
396 0 : printEmployee(employee1);
397 0 : printEmployee(employee2);
398 0 : printEmployee(employee3);
399 0 : printDepartment(department1);
400 0 : printDepartment(department2);
401 :
402 :
403 : // Saves created data file
404 :
405 0 : std::cout << "\n[OKS TUTORIAL]: Saves created OKS data file...\n";
406 :
407 0 : kernel.save_data(data_h);
408 :
409 :
410 0 : std::cout << "[OKS TUTORIAL]: Done with saving created OKS data file\n";
411 :
412 :
413 : // **********************************************************************
414 : // ***** At this moment the database has been created and saved *****
415 : // **********************************************************************
416 :
417 :
418 0 : std::cout << "\n[OKS TUTORIAL]: Start database querying tests\n\n";
419 :
420 :
421 : // This is a test for OksComparator and OksQuery
422 :
423 0 : {
424 0 : std::cout << "[QUERY]: Start simple database querying...\n";
425 :
426 : // Looking for persons were born after 01 January 1960
427 :
428 0 : boost::gregorian::date aDate(boost::gregorian::from_string("1960/01/01")); // query date
429 0 : OksQuery query(true, new OksComparator(PersonBirthday, new OksData(aDate), OksQuery::greater_cmp));
430 :
431 :
432 : // executes query
433 :
434 0 : std::cout << "[QUERY]: Looking for persons were born after " << aDate << " ...\n\n";
435 :
436 0 : OksObject::List * queryResult = Person->execute_query(&query);
437 :
438 :
439 : // builds iterator over results if something was found
440 :
441 0 : if(queryResult) {
442 0 : std::cout << "[QUERY]: Query \'" << query
443 : << "\'\n founds the following objects in class \'"
444 0 : << Person->get_name() << "\' and subclasses:\n";
445 :
446 0 : for(OksObject::List::iterator i = queryResult->begin(); i != queryResult->end(); ++i) {
447 0 : OksObject * o = *i;
448 0 : OksData * d(o->GetAttributeValue("Birthday"));
449 0 : std::cout << " - " << o << " was born " << *d << std::endl;
450 : }
451 :
452 :
453 : // free list: we do not need it anymore
454 :
455 0 : delete queryResult;
456 : }
457 :
458 0 : std::cout << "[QUERY]: Done with simple database querying\n\n";
459 0 : }
460 :
461 0 : {
462 0 : std::cout << "[QUERY]: Start database querying with logical function...\n";
463 :
464 :
465 : // Looking for persons were born after 01 January 1960
466 : // and before 01 January 1970
467 :
468 0 : boost::gregorian::date lowDate(boost::gregorian::from_string("1960/01/01")); // low date
469 0 : boost::gregorian::date highDate(boost::gregorian::from_string("1970/01/01")); // high date
470 :
471 0 : OksAndExpression * andExpression = new OksAndExpression();
472 :
473 0 : andExpression->add(new OksComparator(PersonBirthday, new OksData(lowDate), OksQuery::greater_cmp));
474 0 : andExpression->add(new OksComparator(PersonBirthday, new OksData(highDate), OksQuery::less_cmp));
475 :
476 0 : OksQuery query(true, andExpression);
477 :
478 :
479 : // executes query
480 :
481 0 : std::cout << "[QUERY]: Looking for persons were born between " << lowDate
482 0 : << " and " << highDate << " ...\n\n";
483 :
484 0 : OksObject::List * queryResult = Person->execute_query(&query);
485 :
486 :
487 : // builds iterator over results if something was found
488 :
489 0 : if(queryResult) {
490 0 : std::cout << "[QUERY]: Query \'" << query
491 : << "\'\n founds the following objects in class \'"
492 0 : << Person->get_name() << "\' and subclasses:\n";
493 :
494 0 : for(OksObject::List::iterator i = queryResult->begin(); i != queryResult->end(); ++i) {
495 0 : OksObject * o = *i;
496 0 : OksData * d(o->GetAttributeValue("Birthday"));
497 0 : std::cout << " - " << o << " was born " << *d << std::endl;
498 : }
499 :
500 :
501 : // free list: we do not need it anymore
502 :
503 0 : delete queryResult;
504 : }
505 :
506 0 : std::cout << "[QUERY]: Done database querying with logical function\n\n";
507 :
508 0 : }
509 :
510 0 : {
511 :
512 0 : std::cout << "[QUERY]: Start database querying with relationship expression...\n";
513 :
514 :
515 : // Looking for employee were born after 01 January 1971
516 : // and which works at IT Department
517 :
518 0 : boost::gregorian::date aDate(boost::gregorian::from_string("1971/01/01")); // a date
519 0 : const char * departmentName = "IT Department";
520 :
521 0 : OksAndExpression * andExpression = new OksAndExpression();
522 :
523 0 : andExpression->add(new OksComparator(PersonBirthday, new OksData(aDate), OksQuery::greater_cmp));
524 0 : andExpression->add(new OksRelationshipExpression(WorksAt, new OksComparator(DepartmentName, new OksData(departmentName), OksQuery::equal_cmp)));
525 :
526 0 : OksQuery query(true, andExpression);
527 :
528 :
529 : // executes query
530 :
531 0 : std::cout << "[QUERY]: Looking for employee were born after " << aDate
532 0 : << " and works at department " << departmentName << " ...\n\n";
533 :
534 0 : OksObject::List * queryResult = Employee->execute_query(&query);
535 :
536 :
537 : // builds iterator over results if something was found
538 :
539 0 : if(queryResult) {
540 0 : std::cout << "[QUERY]: Query \'" << query
541 : << "\'\n founds the following objects in class \'"
542 0 : << Employee->get_name() << "\' and subclasses:\n";
543 :
544 0 : for(OksObject::List::iterator i = queryResult->begin(); i != queryResult->end(); ++i) {
545 0 : OksObject * o = *i;
546 0 : OksData * d(o->GetAttributeValue("Birthday"));
547 0 : std::cout << " - " << o << " was born " << *d << std::endl;
548 : }
549 :
550 :
551 : // free list: we do not need it anymore
552 :
553 0 : delete queryResult;
554 : }
555 :
556 0 : std::cout << "[QUERY]: Done database querying with relationship expression...\n";
557 0 : }
558 :
559 0 : std::cout << "\n[OKS TUTORIAL]: Done with database querying tests\n\n";
560 :
561 : // It is not necessary to free data or schema because all instances of OKS
562 : // classes are automatic C++ objects and they will deleted before last
563 : // close bracket `}`.
564 :
565 : }
566 0 : catch (const std::exception & ex) {
567 0 : std::cerr << "Caught exception:\n" << ex.what() << std::endl;
568 0 : }
569 :
570 : // returns success
571 :
572 0 : return 0;
573 0 : }
|