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/attribute.hpp"
31 : #include "oks/class.hpp"
32 : #include "oks/exceptions.hpp"
33 : #include "oks/kernel.hpp"
34 : #include "oks/object.hpp"
35 : #include "oks/query.hpp"
36 : #include "oks/relationship.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(OksObject* o, // OKS object describing person
47 : const char* name, // new person name
48 : boost::gregorian::date birthday, // new person birthday
49 : const char* familySituation // new person family situation
50 : )
51 : {
52 0 : OksData d; // creates OKS data with unknown type
53 :
54 0 : d.Set(name); // sets OKS data to string 'name'
55 0 : o->SetAttributeValue("Name", &d);
56 :
57 0 : d.Set(birthday); // sets OKS data to date 'birthday'
58 0 : o->SetAttributeValue("Birthday", &d);
59 :
60 0 : d.Set(familySituation); // sets OKS data to 'familySituation'
61 0 : d.type = OksData::enum_type; // sets OKS data type to enumeration
62 0 : o->SetAttributeValue("Family_Situation", &d);
63 0 : }
64 :
65 : //
66 : // This function prints an instance of class 'Person'
67 : //
68 :
69 : void
70 0 : printPerson(const OksObject* o // OKS object describing person
71 : )
72 : {
73 0 : OksData* name(o->GetAttributeValue("Name")); // is used to store 'Name'
74 0 : OksData* birthday(o->GetAttributeValue("Birthday")); // is used to store 'Birthday'
75 0 : OksData* family(o->GetAttributeValue("Family_Situation")); // is used to store 'Family_Situation'
76 :
77 0 : std::cout << "Object " << o
78 : << " \n"
79 0 : " Name: "
80 0 : << *name
81 : << " \n"
82 0 : " Birthday: \'"
83 0 : << *birthday
84 : << "\" \n"
85 0 : " Family_Situation: "
86 0 : << *family << std::endl;
87 0 : }
88 :
89 : //
90 : // This function sets attribute values of class 'Employee'
91 : //
92 :
93 : void
94 0 : setEmployeeValues(OksObject* o, // OKS object that describes employee
95 : const char* name, // new employee name
96 : boost::gregorian::date birthday, // new employee birthday
97 : const char* familySituation, // new employee family situation
98 : uint32_t salary // new employee salary situation
99 : )
100 : {
101 : // we can use setPersonValues() because 'Employee' class
102 : // derived from 'Person' class
103 :
104 0 : setPersonValues(o, name, birthday, familySituation);
105 :
106 0 : OksData d(salary); // creates OKS data with ulong 'salary'
107 0 : o->SetAttributeValue("Salary", &d);
108 0 : }
109 :
110 : //
111 : // This function prints an instance of class 'Employee'
112 : //
113 :
114 : void
115 0 : printEmployee(const OksObject* o // OKS object that describes employee
116 : )
117 : {
118 : // we can use printPerson() because 'Employee' class
119 : // is derived from 'Person' class
120 :
121 0 : printPerson(o);
122 :
123 0 : OksData *department(o->GetRelationshipValue("Works at")), // is used to store 'Works at'
124 0 : *salary(o->GetAttributeValue("Salary")); // is used to store 'salary'
125 :
126 0 : std::cout << " Salary: " << *salary
127 : << " \n"
128 : " Works at: \""
129 0 : << department->data.OBJECT->GetId() << "\"\n";
130 0 : }
131 :
132 : //
133 : // This function sets attribute values of class 'Department'
134 : //
135 :
136 : void
137 0 : setDepartmentValues(OksObject* o, // OKS object that describes department
138 : const char* name // new department name
139 : )
140 : {
141 0 : OksData d(name); // creates OKS data with string 'name'
142 :
143 0 : o->SetAttributeValue("Name", &d);
144 0 : }
145 :
146 : //
147 : // This function prints an instance of class 'Department'
148 : //
149 :
150 : void
151 0 : printDepartment(const OksObject* o // OKS object that describes department
152 : )
153 : {
154 0 : OksData *name(o->GetAttributeValue("Name")), // is used to store 'Staff'
155 0 : *staff(o->GetRelationshipValue("Staff")); // is used to store 'Name'
156 :
157 0 : std::cout << "Object " << o
158 : << "\n"
159 0 : " Name: "
160 0 : << *name
161 : << " \n"
162 0 : " Staff: \""
163 0 : << *staff << "\"\n";
164 0 : }
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 (argc > 1 &&
173 0 : (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--h") || !strcmp(argv[1], "-h"))) {
174 0 : std::cout << "Usage: " << argv[0] << " [new_schema new_data]\n";
175 0 : return 0;
176 : }
177 :
178 0 : if (argc == 3) {
179 0 : schema_file = argv[1];
180 0 : data_file = argv[2];
181 : }
182 :
183 : // Creates OKS kernel
184 :
185 0 : std::cout << "[OKS TUTORIAL]: Creating OKS kernel...\n";
186 :
187 0 : OksKernel kernel(false, false, false, false);
188 :
189 0 : std::cout << "[OKS TUTORIAL]: Done creating OKS kernel\n\n";
190 :
191 0 : try {
192 :
193 : // Creates new schema file and tests return status
194 :
195 0 : std::cout << "[OKS TUTORIAL]: Creating new schema file...\n";
196 :
197 0 : OksFile* schema_h = kernel.new_schema(schema_file);
198 :
199 0 : std::cout << "[OKS TUTORIAL]: Done creating new schema file...\n\n"
200 : "[OKS TUTORIAL]: Define database class schema...\n\n"
201 : " ********** ************ 1..1 **************\n"
202 : " * Person *<|------* Employee *--------<>* Department *\n"
203 0 : " ********** ************ 0..N **************\n\n";
204 :
205 : // Creates class Person with three attributes "Name", "Birthday" and "Family_Situation"
206 :
207 0 : OksClass* Person = new OksClass("Person", "It is a class to describe a person", false, &kernel);
208 :
209 0 : Person->add(new OksAttribute(
210 0 : "Name", OksAttribute::string_type, false, "", "Unknown", "A string to describe person name", true));
211 :
212 0 : OksAttribute* PersonBirthday = new OksAttribute(
213 0 : "Birthday", OksAttribute::date_type, false, "", "2009/01/01", "A date to describe person birthday", true);
214 :
215 0 : Person->add(PersonBirthday);
216 :
217 0 : Person->add(new OksAttribute("Family_Situation",
218 : OksAttribute::enum_type,
219 : false,
220 : "Single,Married,Widow(er)",
221 : "Single",
222 : "A enumeration to describe a person family state",
223 0 : true));
224 :
225 : // Creates class Person with superclass Person, add "Salary" attribute and "Works at" relationship
226 :
227 0 : OksClass* Employee = new OksClass("Employee", "It is a class to describe an employee", false, &kernel);
228 :
229 0 : OksAttribute* EmployeeSalary = new OksAttribute(
230 0 : "Salary", OksAttribute::u32_int_type, false, "", "1000", "An integer to describe employee salary", false);
231 :
232 0 : OksRelationship* WorksAt = new OksRelationship("Works at",
233 : "Department",
234 : OksRelationship::One,
235 : OksRelationship::One,
236 : false,
237 : false,
238 : false,
239 0 : "A employee works at one and only one department");
240 :
241 0 : Employee->add_super_class("Person");
242 0 : Employee->add(EmployeeSalary);
243 0 : Employee->add(WorksAt);
244 :
245 : // Creates class Department with one attribute and one relationship
246 :
247 0 : OksClass* Department = new OksClass("Department", "It is a class to describe a department", false, &kernel);
248 :
249 0 : OksAttribute* DepartmentName = new OksAttribute(
250 0 : "Name", OksAttribute::string_type, false, "", "Unknown", "A string to describe department name", true);
251 :
252 0 : OksRelationship* DepartmentStaff = new OksRelationship("Staff",
253 : "Employee",
254 : OksRelationship::Zero,
255 : OksRelationship::Many,
256 : true,
257 : true,
258 : true,
259 0 : "A department has zero or many employess");
260 :
261 0 : Department->add(DepartmentName);
262 0 : Department->add(DepartmentStaff);
263 :
264 : // Saves created schema file
265 :
266 0 : std::cout << "[OKS TUTORIAL]: Saves created OKS schema file...\n";
267 :
268 0 : kernel.save_schema(schema_h);
269 :
270 : // Creates new data file and tests return status
271 :
272 0 : std::cout << "[OKS TUTORIAL]: Creating new data file...\n";
273 :
274 0 : OksFile* data_h = kernel.new_data(data_file, "OKS TUTORIAL DATA FILE");
275 :
276 0 : data_h->add_include_file(schema_file);
277 :
278 : // Creates instances of the classes
279 :
280 0 : OksObject* person1 = new OksObject(Person, "peter");
281 0 : OksObject* person2 = new OksObject(Person, "mick");
282 0 : OksObject* person3 = new OksObject(Person, "baby");
283 0 : OksObject* employee1 = new OksObject(Employee, "alexander");
284 0 : OksObject* employee2 = new OksObject(Employee, "michel");
285 0 : OksObject* employee3 = new OksObject(Employee, "maria");
286 0 : OksObject* department1 = new OksObject(Department, "IT");
287 0 : OksObject* department2 = new OksObject(Department, "EP");
288 :
289 : // Sets attribute values for instances of class 'Person'
290 :
291 0 : setPersonValues(person1, "Peter", boost::gregorian::from_string("1960/02/01"), "Married");
292 0 : setPersonValues(person2, "Mick", boost::gregorian::from_string("1956-09-01"), "Single");
293 0 : setPersonValues(person3, "Julia", boost::gregorian::from_string("2000-May-25"), "Single");
294 :
295 : // Sets attribute values for instances of class 'Employee'
296 :
297 0 : setEmployeeValues(employee1, "Alexander", boost::gregorian::from_string("1972/05/12"), "Single", 3540);
298 0 : setEmployeeValues(employee2, "Michel", boost::gregorian::from_string("1963/01/28"), "Married", 4950);
299 0 : setEmployeeValues(employee3, "Maria", boost::gregorian::from_string("1951/08/18"), "Widow(er)", 4020);
300 :
301 : // Sets attribute values for instance of class 'Department'
302 :
303 0 : setDepartmentValues(department1, "IT Department");
304 0 : setDepartmentValues(department2, "EP Department");
305 :
306 : // Sets relationships
307 :
308 0 : department1->AddRelationshipValue("Staff", employee1);
309 0 : department1->AddRelationshipValue("Staff", employee2);
310 0 : department2->AddRelationshipValue("Staff", employee3);
311 0 : employee1->SetRelationshipValue("Works at", department1);
312 0 : employee2->SetRelationshipValue("Works at", department1);
313 0 : employee3->SetRelationshipValue("Works at", department2);
314 :
315 : // Print out database contents
316 :
317 0 : std::cout << "\n[OKS TUTORIAL]: Database contains the following data:\n";
318 :
319 0 : printPerson(person1);
320 0 : printPerson(person2);
321 0 : printPerson(person3);
322 0 : printEmployee(employee1);
323 0 : printEmployee(employee2);
324 0 : printEmployee(employee3);
325 0 : printDepartment(department1);
326 0 : printDepartment(department2);
327 :
328 : // Saves created data file
329 :
330 0 : std::cout << "\n[OKS TUTORIAL]: Saves created OKS data file...\n";
331 :
332 0 : kernel.save_data(data_h);
333 :
334 0 : std::cout << "[OKS TUTORIAL]: Done with saving created OKS data file\n";
335 :
336 : // **********************************************************************
337 : // ***** At this moment the database has been created and saved *****
338 : // **********************************************************************
339 :
340 0 : std::cout << "\n[OKS TUTORIAL]: Start database querying tests\n\n";
341 :
342 : // This is a test for OksComparator and OksQuery
343 :
344 0 : {
345 0 : std::cout << "[QUERY]: Start simple database querying...\n";
346 :
347 : // Looking for persons were born after 01 January 1960
348 :
349 0 : boost::gregorian::date aDate(boost::gregorian::from_string("1960/01/01")); // query date
350 0 : OksQuery query(true, new OksComparator(PersonBirthday, new OksData(aDate), OksQuery::greater_cmp));
351 :
352 : // executes query
353 :
354 0 : std::cout << "[QUERY]: Looking for persons were born after " << aDate << " ...\n\n";
355 :
356 0 : OksObject::List* queryResult = Person->execute_query(&query);
357 :
358 : // builds iterator over results if something was found
359 :
360 0 : if (queryResult) {
361 0 : std::cout << "[QUERY]: Query \'" << query << "\'\n founds the following objects in class \'"
362 0 : << Person->get_name() << "\' and subclasses:\n";
363 :
364 0 : for (OksObject::List::iterator i = queryResult->begin(); i != queryResult->end(); ++i) {
365 0 : OksObject* o = *i;
366 0 : OksData* d(o->GetAttributeValue("Birthday"));
367 0 : std::cout << " - " << o << " was born " << *d << std::endl;
368 : }
369 :
370 : // free list: we do not need it anymore
371 :
372 0 : delete queryResult;
373 : }
374 :
375 0 : std::cout << "[QUERY]: Done with simple database querying\n\n";
376 0 : }
377 :
378 0 : {
379 0 : std::cout << "[QUERY]: Start database querying with logical function...\n";
380 :
381 : // Looking for persons were born after 01 January 1960
382 : // and before 01 January 1970
383 :
384 0 : boost::gregorian::date lowDate(boost::gregorian::from_string("1960/01/01")); // low date
385 0 : boost::gregorian::date highDate(boost::gregorian::from_string("1970/01/01")); // high date
386 :
387 0 : OksAndExpression* andExpression = new OksAndExpression();
388 :
389 0 : andExpression->add(new OksComparator(PersonBirthday, new OksData(lowDate), OksQuery::greater_cmp));
390 0 : andExpression->add(new OksComparator(PersonBirthday, new OksData(highDate), OksQuery::less_cmp));
391 :
392 0 : OksQuery query(true, andExpression);
393 :
394 : // executes query
395 :
396 0 : std::cout << "[QUERY]: Looking for persons were born between " << lowDate << " and " << highDate << " ...\n\n";
397 :
398 0 : OksObject::List* queryResult = Person->execute_query(&query);
399 :
400 : // builds iterator over results if something was found
401 :
402 0 : if (queryResult) {
403 0 : std::cout << "[QUERY]: Query \'" << query << "\'\n founds the following objects in class \'"
404 0 : << Person->get_name() << "\' and subclasses:\n";
405 :
406 0 : for (OksObject::List::iterator i = queryResult->begin(); i != queryResult->end(); ++i) {
407 0 : OksObject* o = *i;
408 0 : OksData* d(o->GetAttributeValue("Birthday"));
409 0 : std::cout << " - " << o << " was born " << *d << std::endl;
410 : }
411 :
412 : // free list: we do not need it anymore
413 :
414 0 : delete queryResult;
415 : }
416 :
417 0 : std::cout << "[QUERY]: Done database querying with logical function\n\n";
418 0 : }
419 :
420 0 : {
421 :
422 0 : std::cout << "[QUERY]: Start database querying with relationship expression...\n";
423 :
424 : // Looking for employee were born after 01 January 1971
425 : // and which works at IT Department
426 :
427 0 : boost::gregorian::date aDate(boost::gregorian::from_string("1971/01/01")); // a date
428 0 : const char* departmentName = "IT Department";
429 :
430 0 : OksAndExpression* andExpression = new OksAndExpression();
431 :
432 0 : andExpression->add(new OksComparator(PersonBirthday, new OksData(aDate), OksQuery::greater_cmp));
433 0 : andExpression->add(new OksRelationshipExpression(
434 0 : WorksAt, new OksComparator(DepartmentName, new OksData(departmentName), OksQuery::equal_cmp)));
435 :
436 0 : OksQuery query(true, andExpression);
437 :
438 : // executes query
439 :
440 0 : std::cout << "[QUERY]: Looking for employee were born after " << aDate << " and works at department "
441 0 : << departmentName << " ...\n\n";
442 :
443 0 : OksObject::List* queryResult = Employee->execute_query(&query);
444 :
445 : // builds iterator over results if something was found
446 :
447 0 : if (queryResult) {
448 0 : std::cout << "[QUERY]: Query \'" << query << "\'\n founds the following objects in class \'"
449 0 : << Employee->get_name() << "\' and subclasses:\n";
450 :
451 0 : for (OksObject::List::iterator i = queryResult->begin(); i != queryResult->end(); ++i) {
452 0 : OksObject* o = *i;
453 0 : OksData* d(o->GetAttributeValue("Birthday"));
454 0 : std::cout << " - " << o << " was born " << *d << std::endl;
455 : }
456 :
457 : // free list: we do not need it anymore
458 :
459 0 : delete queryResult;
460 : }
461 :
462 0 : std::cout << "[QUERY]: Done database querying with relationship expression...\n";
463 0 : }
464 :
465 0 : std::cout << "\n[OKS TUTORIAL]: Done with database querying tests\n\n";
466 :
467 : // It is not necessary to free data or schema because all instances of OKS
468 : // classes are automatic C++ objects and they will deleted before last
469 : // close bracket `}`.
470 :
471 0 : } catch (const std::exception& ex) {
472 0 : std::cerr << "Caught exception:\n" << ex.what() << std::endl;
473 0 : }
474 :
475 : // returns success
476 :
477 0 : return 0;
478 0 : }
|