Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
EmployeesDB.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include <iostream>
7#include <random>
8
10#include "Stroika/Foundation/DataExchange/ObjectVariantMapper.h"
16
17#include "EmployeesDB.h"
18
19using namespace std;
20
21using namespace Stroika::Foundation;
23using namespace Stroika::Foundation::Common;
25using namespace Stroika::Foundation::Database;
27using namespace Stroika::Foundation::Debug;
28using namespace Stroika::Foundation::Execution;
29
30using namespace Database::Document;
31
32namespace {
33
34 /*
35 * Sample data to write to the database
36 */
37 struct Employee {
38 optional<IDType> ID{};
39 String fName;
40 int fAge{};
41 String fAddress;
42 double fSalary{};
43 bool fStillEmployed{};
44
45 static const ObjectVariantMapper kMapper;
46 };
47 /*
48 * Define mapping to VariantValues (think JSON)
49 */
50 const ObjectVariantMapper Employee::kMapper{[] () {
52 mapper.AddCommonType<optional<IDType>> ();
53 mapper.AddClass<Employee> ({
54 {"id"sv, &Employee::ID},
55 {"Name"sv, &Employee::fName},
56 {"Age"sv, &Employee::fAge},
57 {"Address"sv, &Employee::fAddress},
58 {"Salary"sv, &Employee::fSalary},
59 {"Still-Employed"sv, &Employee::fStillEmployed},
60 });
61 return mapper;
62 }()};
63
64 /*
65 * Sample data to write to the database
66 */
67 struct Paycheck {
68 optional<IDType> ID{};
69 IDType fEmployeeRef;
70 double fAmount{};
71 Time::Date fDate;
72
73 static const ObjectVariantMapper kMapper;
74 };
75 /*
76 * Define mapping to VariantValues (think JSON)
77 */
78 const ObjectVariantMapper Paycheck::kMapper{[] () {
80 mapper.AddCommonType<optional<int>> ();
81 mapper.AddClass<Paycheck> ({
82 {"id"sv, &Paycheck::ID},
83 {"Employee-Ref"sv, &Paycheck::fEmployeeRef},
84 {"Amount"sv, &Paycheck::fAmount},
85 {"Date"sv, &Paycheck::fDate},
86 });
87 return mapper;
88 }()};
89
90 /**
91 * Combine all the ObjectVariantMappers for the objects we use in this database into one, and
92 * AMEND any mappers as needed to accommodate possible changes in the mappings (like representing
93 * some things as strings vs. BLOBs etc).
94 */
95 const ObjectVariantMapper kDBObjectMapper_{[] () {
97 mapper += Employee::kMapper;
98 mapper += Paycheck::kMapper;
99 return mapper;
100 }()};
101
102 /*
103 * Example thread making updates to the employees table.
104 */
105 void PeriodicallyUpdateEmployeesTable_ (Connection::Ptr conn)
106 {
107 TraceContextBumper ctx{"{}::PeriodicallyUpdateEmployeesTable_"};
108
109 conn.CreateCollection ("Employees");
110 ObjectCollection::Ptr<Employee> employeeCollection = ObjectCollection::New<Employee> (conn.GetCollection ("Employees"), kDBObjectMapper_);
111
112 // Add Initial Employees
113 try {
114 employeeCollection.Add (Employee{.fName = "Paul", .fAge = 32, .fAddress = "California", .fSalary = 20000.00, .fStillEmployed = true});
115 employeeCollection.Add (Employee{.fName = "Allen", .fAge = 25, .fAddress = "Texas", .fSalary = 15000.00, .fStillEmployed = true});
116 employeeCollection.Add (Employee{.fName = "Teddy", .fAge = 23, .fAddress = "Norway", .fSalary = 20000.00, .fStillEmployed = true});
117 employeeCollection.Add (Employee{.fName = "Mark", .fAge = 25, .fAddress = "Rich-Mond", .fSalary = 65000.00, .fStillEmployed = true});
118 employeeCollection.Add (Employee{.fName = "David", .fAge = 27, .fAddress = "Texas", .fSalary = 85000.00, .fStillEmployed = true});
119 employeeCollection.Add (Employee{.fName = "Kim", .fAge = 22, .fAddress = "South-Hall", .fSalary = 45000.00, .fStillEmployed = true});
120 employeeCollection.Add (Employee{.fName = "James", .fAge = 24, .fAddress = "Houston", .fSalary = 10000.00, .fStillEmployed = true});
121 }
122 catch (...) {
123 cerr << "\tException adding initial employees to DB - this should generally not happen: {}"_f(current_exception ()) << endl;
124 }
125
126 default_random_engine generator;
127 uniform_int_distribution<int> distribution{1, 6};
128
129 // then keep adding/removing people randomly (but dont really remove just mark no longer employed so we
130 // can REF in paycheck table
131 while (true) {
132 static const Sequence<String> kNames_{"Joe", "Phred", "Barny", "Sue", "Anne"};
133 uniform_int_distribution<int> namesDistr{0, static_cast<int> (kNames_.size () - 1)};
134 uniform_int_distribution<int> ageDistr{25, 50};
135 static const Sequence<String> kAddresses{"Houston", "Pittsburg", "New York", "Paris", "California"};
136 uniform_int_distribution<int> addressesDistr{0, static_cast<int> (kAddresses.size () - 1)};
137 uniform_real_distribution<float> salaryDistr{10000.00, 50000.00};
138
139 try {
140 uniform_int_distribution<int> whatTodoDistr{0, 3};
141 switch (whatTodoDistr (generator)) {
142 case 0:
143 case 1: {
144 String name = kNames_[namesDistr (generator)];
145 cout << "\tAdding employee {}"_f(name) << endl;
146 employeeCollection.Add (Employee{nullopt, name, ageDistr (generator), kAddresses[addressesDistr (generator)],
147 salaryDistr (generator), true});
148 } break;
149 case 2: {
150 // Look somebody up, and fire them
151 auto activeEmps = employeeCollection.GetAll ();
152 if (not activeEmps.empty ()) {
153 uniform_int_distribution<int> empDistr{0, static_cast<int> (activeEmps.size () - 1)};
154 Employee killMe = activeEmps[empDistr (generator)];
155 Assert (killMe.ID.has_value ());
156 cout << "\tFiring employee: {}, {}"_f(*killMe.ID, killMe.fName) << endl;
157 killMe.fStillEmployed = false;
158 employeeCollection.Replace (*killMe.ID, killMe);
159 // employeeTableConnection->Update (killMe);
160 }
161 } break;
162 }
163 }
164 catch (...) {
165 // no need to check for ThreadAbort exception, since Sleep is a cancelation point
166 cerr << "\tException updating database: this should generally not happen: {}"_f(current_exception ()) << endl;
167 }
168
169 Sleep (1s); // **cancelation point**
170 }
171 }
172
173 /*
174 * Example thread making updates to the paychecks table (while consulting the employees table).
175 */
176 void PeriodicallyWriteChecksForEmployeesTable_ (Connection::Ptr conn)
177 {
178 TraceContextBumper ctx{"{}::PeriodicallyWriteChecksForEmployeesTable_"};
179 conn.CreateCollection ("Employees");
180 ObjectCollection::Ptr<Employee> employeeCollection = ObjectCollection::New<Employee> (conn.GetCollection ("Employees"), kDBObjectMapper_);
181 conn.CreateCollection ("Paychecks");
182 ObjectCollection::Ptr<Paycheck> paycheckCollection = ObjectCollection::New<Paycheck> (conn.GetCollection ("Paychecks"), kDBObjectMapper_);
183
184 while (true) {
185 try {
186 for (const auto& employee : employeeCollection.GetAll ()) {
187 Assert (employee.ID != nullopt);
188 cout << "\tWriting paycheck for employee #{} ({}) amount {}"_f(*employee.ID, employee.fName, employee.fSalary) << endl;
189 paycheckCollection.Add (Paycheck{nullopt, *employee.ID, employee.fSalary / 12, DateTime::Now ().GetDate ()});
190 }
191 }
192 catch (...) {
193 // no need to check for ThreadAbort exception, since Sleep is a cancelation point
194 cout << "\tException processing paychecks - this should generally not happen: {}"_f(current_exception ()) << endl;
195 }
196 Sleep (2s); // **cancelation point**
197 }
198 }
199}
200
201void Stroika::Samples::Document::EmployeesDB (const function<Connection::Ptr ()>& connectionFactory)
202{
203 TraceContextBumper ctx{"EmployeesDB"};
204
205 Connection::Ptr conn1 = connectionFactory ();
206 Connection::Ptr conn2 = connectionFactory ();
207
208 /*
209 * Create threads for each of our activities.
210 * When the waitable even times out, the threads will automatically be 'canceled' as they go out of scope.
211 */
212 Thread::CleanupPtr updateEmpDBThread{Thread::CleanupPtr::eAbortBeforeWaiting,
213 Thread::New ([=] () { PeriodicallyUpdateEmployeesTable_ (conn1); }, Thread::eAutoStart, "Update Employee Table"sv)};
214 Thread::CleanupPtr writeChecks{Thread::CleanupPtr::eAbortBeforeWaiting,
215 Thread::New ([=] () { PeriodicallyWriteChecksForEmployeesTable_ (conn2); }, Thread::eAutoStart, "Write Checks"sv)};
217}
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A generalization of a vector: a container whose elements are keyed by the natural numbers.
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
nonvirtual void AddClass(const Traversal::Iterable< StructFieldInfo > &fieldDescriptions, const ClassMapperOptions< CLASS > &mapperOptions={})
nonvirtual void AddCommonType(ARGS &&... args)
nonvirtual WaitStatus WaitQuietly(Time::DurationSeconds timeout=Time::kInfinity)
Ptr New(const function< void()> &fun2CallOnce, const optional< Characters::String > &name, const optional< Configuration > &configuration)
Definition Thread.cpp:955
void Sleep(Time::Duration seconds2Wait)
Definition Sleep.cpp:18
STL namespace.