7#include <unordered_map>
15 std::vector<std::string> Values;
19 std::vector<std::string> Columns;
20 std::vector<StdRow> Rows;
23 struct InMemoryDatabaseBackend::Impl {
24 std::unordered_map<std::string, StdTable> m_tables;
26 void ExecuteCreate(
const std::vector<std::string>& tokens) {
28 if (tokens.size() > 2 && ToUpper(tokens[1]) ==
"TABLE") {
29 std::string tableName = tokens[2];
32 while (idx < tokens.size()) {
33 if (tokens[idx] ==
"(" || tokens[idx] ==
")") {
37 std::string colName = tokens[idx];
39 if (idx < tokens.size() && tokens[idx] !=
"," && tokens[idx] !=
")") {
42 t.Columns.push_back(colName);
43 if (idx < tokens.size() && tokens[idx] ==
",") {
47 m_tables[tableName] = t;
51 void ExecuteInsert(
const std::vector<std::string>& tokens,
52 const std::unordered_map<std::string, std::string>& parameters,
55 if (tokens.size() > 2 && ToUpper(tokens[1]) ==
"INTO") {
56 std::string tableName = tokens[2];
57 auto tIt = m_tables.find(tableName);
58 if (tIt == m_tables.end())
return;
60 StdTable& t = tIt->second;
61 std::vector<std::string> cols;
62 std::vector<std::string> vals;
65 if (idx < tokens.size() && tokens[idx] ==
"(") {
67 while (idx < tokens.size() && tokens[idx] !=
")") {
68 cols.push_back(tokens[idx]);
71 if (idx < tokens.size()) idx++;
74 if (idx < tokens.size() && ToUpper(tokens[idx]) ==
"VALUES") {
78 if (idx < tokens.size() && tokens[idx] ==
"(") {
80 while (idx < tokens.size() && tokens[idx] !=
")") {
81 vals.push_back(ResolveValue(tokens[idx], parameters));
87 r.Values.resize(t.Columns.size());
90 for (
size_t i = 0; i < t.Columns.size() && i < vals.size(); ++i) {
91 r.Values[i] = vals[i];
94 for (
size_t i = 0; i < cols.size() && i < vals.size(); ++i) {
95 auto colName = cols[i];
96 auto cIt = std::find(t.Columns.begin(), t.Columns.end(), colName);
97 if (cIt != t.Columns.end()) {
98 size_t colIdx = std::distance(t.Columns.begin(), cIt);
99 r.Values[colIdx] = vals[i];
108 std::vector<StdRow> ExecuteSelect(
const std::vector<std::string>& tokens,
109 const std::unordered_map<std::string, std::string>& parameters,
110 std::vector<std::string>& columnNames) {
112 std::vector<std::string> selectCols;
114 while (idx < tokens.size() && ToUpper(tokens[idx]) !=
"FROM") {
115 selectCols.push_back(tokens[idx]);
119 if (idx >= tokens.size())
return {};
121 if (idx >= tokens.size())
return {};
122 std::string tableName = tokens[idx];
125 auto tIt = m_tables.find(tableName);
126 if (tIt == m_tables.end())
return {};
128 StdTable& t = tIt->second;
131 std::string whereCol;
132 std::string whereVal;
133 if (idx < tokens.size() && ToUpper(tokens[idx]) ==
"WHERE") {
135 if (idx < tokens.size()) whereCol = tokens[idx];
137 if (idx < tokens.size() && tokens[idx] ==
"=") {
139 if (idx < tokens.size()) whereVal = ResolveValue(tokens[idx], parameters);
144 std::vector<size_t> colIndices;
145 if (selectCols.size() == 1 && selectCols[0] ==
"*") {
146 columnNames = t.Columns;
147 for (
size_t i = 0; i < t.Columns.size(); ++i) colIndices.push_back(i);
149 for (
auto const& selCol : selectCols) {
150 auto cIt = std::find(t.Columns.begin(), t.Columns.end(), selCol);
151 if (cIt != t.Columns.end()) {
152 columnNames.push_back(selCol);
153 colIndices.push_back(std::distance(t.Columns.begin(), cIt));
158 int whereColIdx = -1;
159 if (!whereCol.empty()) {
160 auto cIt = std::find(t.Columns.begin(), t.Columns.end(), whereCol);
161 if (cIt != t.Columns.end()) {
162 whereColIdx =
static_cast<int>(std::distance(t.Columns.begin(), cIt));
167 std::vector<StdRow> resultRows;
168 for (
auto const& row : t.Rows) {
169 if (whereColIdx != -1) {
170 if (row.Values[whereColIdx] != whereVal) {
175 for (
auto index : colIndices) {
176 newRow.Values.push_back(row.Values[index]);
178 resultRows.push_back(newRow);
183 void ExecuteUpdate(
const std::vector<std::string>& tokens,
184 const std::unordered_map<std::string, std::string>& parameters,
187 std::string tableName = tokens[1];
188 auto tIt = m_tables.find(tableName);
189 if (tIt == m_tables.end())
return;
191 StdTable& t = tIt->second;
194 if (idx < tokens.size() && ToUpper(tokens[idx]) ==
"SET") {
198 std::vector<std::pair<std::string, std::string>> updates;
199 while (idx < tokens.size() && ToUpper(tokens[idx]) !=
"WHERE") {
200 std::string colName = tokens[idx];
202 if (idx < tokens.size() && tokens[idx] ==
"=") {
204 std::string val = ResolveValue(tokens[idx], parameters);
205 updates.push_back({colName, val});
211 std::string whereCol;
212 std::string whereVal;
213 if (idx < tokens.size() && ToUpper(tokens[idx]) ==
"WHERE") {
215 if (idx < tokens.size()) whereCol = tokens[idx];
217 if (idx < tokens.size() && tokens[idx] ==
"=") {
219 if (idx < tokens.size()) whereVal = ResolveValue(tokens[idx], parameters);
223 int whereColIdx = -1;
224 if (!whereCol.empty()) {
225 auto cIt = std::find(t.Columns.begin(), t.Columns.end(), whereCol);
226 if (cIt != t.Columns.end()) {
227 whereColIdx =
static_cast<int>(std::distance(t.Columns.begin(), cIt));
232 for (
auto& row : t.Rows) {
233 if (whereColIdx != -1) {
234 if (row.Values[whereColIdx] != whereVal) {
238 for (
auto const& update : updates) {
239 auto cIt = std::find(t.Columns.begin(), t.Columns.end(), update.first);
240 if (cIt != t.Columns.end()) {
241 size_t updateIdx = std::distance(t.Columns.begin(), cIt);
242 row.Values[updateIdx] = update.second;
249 void ExecuteDelete(
const std::vector<std::string>& tokens,
250 const std::unordered_map<std::string, std::string>& parameters,
253 if (tokens.size() > 2 && ToUpper(tokens[1]) ==
"FROM") {
254 std::string tableName = tokens[2];
255 auto tIt = m_tables.find(tableName);
256 if (tIt == m_tables.end())
return;
258 StdTable& t = tIt->second;
261 std::string whereCol;
262 std::string whereVal;
263 if (idx < tokens.size() && ToUpper(tokens[idx]) ==
"WHERE") {
265 if (idx < tokens.size()) whereCol = tokens[idx];
267 if (idx < tokens.size() && tokens[idx] ==
"=") {
269 if (idx < tokens.size()) whereVal = ResolveValue(tokens[idx], parameters);
273 int whereColIdx = -1;
274 if (!whereCol.empty()) {
275 auto cIt = std::find(t.Columns.begin(), t.Columns.end(), whereCol);
276 if (cIt != t.Columns.end()) {
277 whereColIdx =
static_cast<int>(std::distance(t.Columns.begin(), cIt));
282 auto it = t.Rows.begin();
283 while (it != t.Rows.end()) {
284 if (whereColIdx != -1) {
285 if (it->Values[whereColIdx] == whereVal) {
286 it = t.Rows.erase(it);
291 it = t.Rows.erase(it);
300 std::vector<std::string> Tokenize(
const std::string& s)
const {
302 std::vector<std::string> tokens;
304 bool inQuotes =
false;
305 for (
size_t i = 0; i < s.length(); ++i) {
308 inQuotes = !inQuotes;
310 }
else if (!inQuotes && (c ==
' ' || c ==
',' || c ==
'(' || c ==
')' || c ==
'=')) {
311 if (!token.empty()) {
312 tokens.push_back(token);
315 if (c ==
'(' || c ==
')' || c ==
'=') {
316 tokens.push_back(std::string(1, c));
322 if (!token.empty()) {
323 tokens.push_back(token);
328 std::string ToUpper(std::string s)
const {
330 std::transform(s.begin(), s.end(), s.begin(), ::toupper);
334 std::string ResolveValue(
const std::string& val,
const std::unordered_map<std::string, std::string>& parameters)
const {
336 if (!val.empty() && val[0] ==
'@') {
337 auto it = parameters.find(val);
338 if (it != parameters.end()) {
341 return std::string(
"");
343 if (val.length() >= 2 && val.front() ==
'\'' && val.back() ==
'\'') {
344 return val.substr(1, val.length() - 2);
349 std::vector<StdRow> DispatchCommand(
const std::string& cmd,
const std::vector<std::string>& tokens,
const std::unordered_map<std::string, std::string>& stdParams, std::vector<std::string>& stdColNames,
int& rowsAffected) {
351 if (cmd ==
"CREATE") ExecuteCreate(tokens);
352 else if (cmd ==
"INSERT") ExecuteInsert(tokens, stdParams, rowsAffected);
353 else if (cmd ==
"SELECT")
return ExecuteSelect(tokens, stdParams, stdColNames);
354 else if (cmd ==
"UPDATE") ExecuteUpdate(tokens, stdParams, rowsAffected);
355 else if (cmd ==
"DELETE") ExecuteDelete(tokens, stdParams, rowsAffected);
365 m_pImpl->m_tables.clear();
370 std::unordered_map<std::string, std::string> stdParams;
371 auto keys = parameters.
GetKeys();
372 for (
int i = 0; i < keys.GetLength(); ++i) {
382 for (
const auto& col : stdColNames) columnNames.
Add(
String(col.c_str()));
386 for (
const auto& sr : stdResRows) {
388 for (
const auto& v : sr.Values) r.
Values.Add(
String(v.c_str()));
405 std::unordered_map<std::string, std::string> stdParams =
ConvertParamsMap(parameters);
406 std::vector<std::string> tokens = m_pImpl->Tokenize(sql.
GetRawString());
410 std::vector<std::string> stdColNames;
411 std::vector<StdRow> stdResRows = m_pImpl->DispatchCommand(m_pImpl->ToUpper(tokens[0]), tokens, stdParams, stdColNames, rowsAffected);
Represents a collection of keys and values.
Array< TKey > GetKeys() const
bool TryGetValue(const TKey &key, TValue &value) const
Represents a strongly typed list of objects accessible by index.
void Add(const T &item)
Adds an object to the end of the List.
void Clear()
Removes all elements from the List.
Collections::Generic::List< Row > Execute(const String &sql, const Collections::Generic::Dictionary< String, String > ¶meters, Collections::Generic::List< String > &columnNames, int &rowsAffected) override
Executes a SQL statement (CREATE, INSERT, SELECT, UPDATE, DELETE) in memory.
~InMemoryDatabaseBackend() override
Destructor releasing internal in-memory tables.
void ClearDatabase() override
Clears all tables and rows in the in-memory database.
InMemoryDatabaseBackend()
Initializes a new instance of InMemoryDatabaseBackend.
A unified smart pointer that supports both unique and shared ownership semantics.
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
String()
Initializes a new instance of the String class to an empty string.
const char * GetRawString() const
static Collections::Generic::List< Row > ConvertResultRows(const std::vector< StdRow > &stdResRows, const std::vector< std::string > &stdColNames, Collections::Generic::List< String > &columnNames)
static std::unordered_map< std::string, std::string > ConvertParamsMap(const Collections::Generic::Dictionary< String, String > ¶meters)
Represents an internal data row consisting of a list of column values.
Collections::Generic::List< String > Values
Ordered list of column values as strings.