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