Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
DirectEmployeesDB.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include <cstdlib>
7#include <iostream>
8
10#include "Stroika/Foundation/Containers/Set.h"
14
15#include "DirectEmployeesDB.h"
16
17using namespace std;
18
19using namespace Stroika::Foundation;
22using namespace Stroika::Foundation::Database;
23using namespace Stroika::Foundation::Database::SQL;
24
25void Stroika::Samples::SQL::DirectEmployeesDB (const std::function<Connection::Ptr ()>& connectionFactory)
26{
27 /*
28 ***** CONNECT TO DATABASE ****
29 */
30 Connection::Ptr conn = connectionFactory ();
31
32 /*
33 ***** SETUP SCHEMA ****
34 */
35 // Example schema roughly from https://www.tutorialspoint.com/sqlite/sqlite_insert_query.htm
36 constexpr Common::Version kCurrentVersion_ = Common::Version{1, 0, Common::VersionStage::Alpha, 0};
37 ORM::ProvisionForVersion (conn, kCurrentVersion_,
38 initializer_list<ORM::TableProvisioner>{
39 {"DEPARTMENT"sv,
40 [] (SQL::Connection::Ptr c, optional<Common::Version> v, [[maybe_unused]] Common::Version targetDBVersion) -> void {
41 // for now no upgrade support
42 if (not v) {
43 c.Exec ("CREATE TABLE DEPARTMENT(ID INT PRIMARY KEY NOT NULL,"
44 "NAME CHAR (50) NOT NULL"
45 ");"sv);
46 }
47 }},
48 {"EMPLOYEES"sv,
49 [] (Connection::Ptr c, optional<Common::Version> v, [[maybe_unused]] Common::Version targetDBVersion) -> void {
50 // for now no upgrade support
51 if (not v) {
52 c.Exec ("CREATE TABLE EMPLOYEES("
53 "ID INT PRIMARY KEY NOT NULL," // See example ThreadTest for simple example using AUTOINCREMENT instead of explicit IDs
54 "NAME TEXT NOT NULL,"
55 "AGE INT NOT NULL,"
56 "ADDRESS CHAR(50),"
57 "SALARY REAL"
58 ");"sv);
59 }
60 }},
61 });
62
63 /*
64 ID NAME AGE ADDRESS SALARY
65 ---------- ---------- ---------- ---------- ----------
66 1 Paul 32 California 20000.0
67 2 Allen 25 Texas 15000.0
68 3 Teddy 23 Norway 20000.0
69 4 Mark 25 Rich-Mond 65000.0
70 5 David 27 Texas 85000.0
71 6 Kim 22 South-Hall 45000.0
72 7 James 24 Houston 10000.0
73 */
74 /*
75 ***** INSERT ROWS ****
76 */
77 // Use Statement with named parameters (to avoid sql injection and to add clarity)
78 Statement addDepartment = conn.mkStatement ("INSERT INTO DEPARTMENT (ID, NAME) values (:ID, :NAME);"sv);
79 addDepartment.Execute (initializer_list<Statement::ParameterDescription>{
80 {":ID"sv, 1},
81 {":NAME"sv, "Washing machines"sv},
82 });
83 Statement addEmployeeStatement =
84 conn.mkStatement ("INSERT INTO EMPLOYEES (ID,NAME,AGE,ADDRESS,SALARY) values (:ID, :NAME, :AGE, :ADDRESS, :SALARY);"sv);
85 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
86 {":ID"sv, 1},
87 {":NAME"sv, "Paul"sv},
88 {":AGE"sv, 32},
89 {":ADDRESS"sv, "California"sv},
90 {":SALARY"sv, 20000.00},
91 });
92 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
93 {":ID"sv, 2},
94 {":NAME"sv, "Allen"sv},
95 {":AGE"sv, 25},
96 {":ADDRESS"sv, "Texas"sv},
97 {":SALARY"sv, 15000.00},
98 });
99 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
100 {":ID", 3},
101 {":NAME", "Teddy"sv},
102 {":AGE", 23},
103 {":ADDRESS", "Norway"sv},
104 {":SALARY", 20000.00},
105 });
106 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
107 {":ID", 4},
108 {":NAME", "Mark"sv},
109 {":AGE", 25},
110 {":ADDRESS", "Rich-Mond"sv},
111 {":SALARY", 65000.00},
112 });
113 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
114 {":ID", 5},
115 {":NAME", "David"sv},
116 {":AGE", 27},
117 {":ADDRESS", "Texas"sv},
118 {":SALARY", 85000.00},
119 });
120 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
121 {":ID", 6},
122 {":NAME", "Kim"sv},
123 {":AGE", 22},
124 {":ADDRESS", "South-Hall"sv},
125 {":SALARY", 45000.00},
126 });
127 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
128 {":ID", 7},
129 {":NAME", "James"sv},
130 {":AGE", 24},
131 {":ADDRESS", "Houston"sv},
132 {":SALARY", 10000.00},
133 });
134 /*
135 ***** INSERT ROWS (ERROR CHECKING) ****
136 */
137 // This call will generate a REQUIRE assertion error - terminating your program. Don't violate assertions!
138 if (false) {
139 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
140 {":BAD-ARGUMENT", 7}, // almost as good as static type checking to make sure parameter names match call
141 {":NAME", "James"sv},
142 {":AGE", 24},
143 {":ADDRESS", "Houston"sv},
144 {":SALARY", 10000.00},
145 });
147 }
148
149 try {
150 addEmployeeStatement.Execute (initializer_list<Statement::ParameterDescription>{
151 {":ID", 7},
152 {":NAME", "James"sv},
153 {":AGE", 24},
154 {":ADDRESS", "Houston"sv},
155 {":SALARY", 10000.00},
156 });
157 AssertNotReached (); // RE-USED ID!!! - only detectable at runtime - so exception thrown
158 }
159 catch (...) {
160 cout << "Note good error message: {}"_f(current_exception ()) << endl; // silently ignore this here...
161 }
162
163 /*
164 ***** SIMPLE QUERIES ****
165 */
166 Statement getAllNames = conn.mkStatement ("Select NAME from EMPLOYEES;"sv);
167 Set<String> allNames = getAllNames.GetAllRows (0).Map<Set<String>> ([] (const VariantValue& v) { return v.As<String> (); });
168 Assert ((allNames == Set<String>{"Paul", "Allen", "Kim", "David", "Mark", "James", "Teddy"}));
169
170 // Either rollup using SQL, or using C++ functional (Iterable) wrappers.
171 Statement sumAllSalaries = conn.mkStatement ("select SUM(SALARY) from EMPLOYEES;"sv);
172 [[maybe_unused]] double sumSalaryUsingSQL = sumAllSalaries.GetAllRows (0)[0].As<double> ();
173 Statement getAllSalaries = conn.mkStatement ("select SALARY from EMPLOYEES;"sv);
174 [[maybe_unused]] double sumSalaryUsingIterableApply =
175 getAllSalaries.GetAllRows (0).Map<Iterable<double>> ([] (VariantValue v) { return v.As<double> (); }).SumValue ();
176 Assert (Math::NearlyEquals (sumSalaryUsingSQL, sumSalaryUsingIterableApply));
177}
#define AssertNotReached()
Definition Assertions.h:355
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
nonvirtual Sequence< Row > GetAllRows()
call Reset (), and then GetAllRemainingRows () - which always starts current statement with current b...
Definition Statement.inl:64
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
STL namespace.