Skip to content

Commit ebd31a6

Browse files
committed
db: extract core DB layer and fix MySQL driver include path
- Introduce vix::db as core anti-ORM module - Move MySQL driver under include/vix/db/mysql/ - Fix Database.cpp include to match new driver layout - Prepare DB module for future drivers (SQLite, Postgres, Redis) - Add tools directory for DB-level utilities (migrator moved out of ORM)
1 parent 78ee2a4 commit ebd31a6

7 files changed

Lines changed: 336 additions & 5 deletions

File tree

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ hello_server
4343
*.bak
4444
db.sql
4545
revoir.md
46-
main.cpp
4746
.vix-scripts
4847

4948

CMakeLists.txt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,15 @@ endif()
234234

235235
# Postgres driver sources (future placeholders)
236236
if (VIX_DB_HAS_POSTGRES)
237-
list(APPEND VIX_DB_PUBLIC_HEADERS include/vix/db/postgres/PostgresDriver.hpp)
238-
list(APPEND VIX_DB_SOURCES src/postgres/PostgresDriver.cpp)
237+
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include/vix/db/postgres/PostgresDriver.hpp"
238+
AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/postgres/PostgresDriver.cpp")
239+
list(APPEND VIX_DB_PUBLIC_HEADERS include/vix/db/postgres/PostgresDriver.hpp)
240+
list(APPEND VIX_DB_SOURCES src/postgres/PostgresDriver.cpp)
241+
else()
242+
message(WARNING "[vix_db] postgres enabled but driver sources not found; disabling.")
243+
set(VIX_DB_HAS_POSTGRES OFF)
244+
set(VIX_DB_USE_POSTGRES OFF)
245+
endif()
239246
endif()
240247

241248
# Redis client sources (future placeholders)
@@ -244,6 +251,28 @@ if (VIX_DB_HAS_REDIS)
244251
list(APPEND VIX_DB_SOURCES src/redis/RedisClient.cpp)
245252
endif()
246253

254+
if (VIX_DB_BUILD_TOOLS)
255+
add_executable(vix_db_migrator)
256+
257+
target_sources(vix_db_migrator PRIVATE
258+
${CMAKE_CURRENT_SOURCE_DIR}/tools/migrator/main.cpp
259+
${CMAKE_CURRENT_SOURCE_DIR}/tools/migrator/MigratorCLI.cpp
260+
)
261+
262+
target_link_libraries(vix_db_migrator PRIVATE vix::db)
263+
target_compile_features(vix_db_migrator PRIVATE cxx_std_20)
264+
265+
if (MSVC)
266+
target_compile_options(vix_db_migrator PRIVATE ${_WARNINGS_MSVC})
267+
else()
268+
target_compile_options(vix_db_migrator PRIVATE ${_WARNINGS_GNU})
269+
endif()
270+
271+
install(TARGETS vix_db_migrator
272+
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/vix
273+
)
274+
endif()
275+
247276
# ------------------------------------------------------------------------------
248277
# If building DB standalone (not from umbrella), bring core as subdir
249278
# ------------------------------------------------------------------------------

include/vix/db/db.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include <vix/db/Errors.hpp>
2020
#include <vix/db/Drivers.hpp>
2121
#if VIX_DB_HAS_MYSQL
22-
#include <vix/db/MySQLDriver.hpp>
22+
#include <vix/db/mysql/MySQLDriver.hpp>
2323
#endif
2424
#include <vix/db/ConnectionPool.hpp>
2525
#include <vix/db/Transaction.hpp>

src/Database.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*/
1313
#include <vix/db/Database.hpp>
1414
#if VIX_DB_HAS_MYSQL
15-
#include <vix/db/MySQLDriver.hpp>
15+
#include <vix/db/mysql/MySQLDriver.hpp>
1616
#endif
1717
#include <vix/config/Config.hpp>
1818

tools/migrator/MigratorCLI.cpp

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/**
2+
*
3+
* @file MigratorCLI.cpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2025, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*/
13+
#include "MigratorCLI.hpp"
14+
15+
#include <vix/db/db.hpp>
16+
#include <vix/db/FileMigrationsRunner.hpp>
17+
#include <vix/db/Drivers.hpp>
18+
19+
#include <iostream>
20+
#include <stdexcept>
21+
#include <memory>
22+
23+
namespace vix::db::tools
24+
{
25+
void MigratorCLI::printUsage(const char *prog)
26+
{
27+
std::cout
28+
<< "Vix ORM Migrator\n\n"
29+
<< "Usage:\n"
30+
<< " " << prog << " <host> <user> <pass> <db> migrate [--dir <migrations_dir>]\n"
31+
<< " " << prog << " <host> <user> <pass> <db> rollback --steps <n> [--dir <migrations_dir>]\n"
32+
<< " " << prog << " <host> <user> <pass> <db> status [--dir <migrations_dir>]\n\n"
33+
<< "Examples:\n"
34+
<< " " << prog << " tcp://127.0.0.1:3306 root '' mydb migrate --dir ./migrations\n"
35+
<< " " << prog << " tcp://127.0.0.1:3306 root '' mydb rollback --steps 1\n"
36+
<< " " << prog << " tcp://127.0.0.1:3306 root '' mydb status --dir db/migrations\n";
37+
}
38+
39+
std::string MigratorCLI::getFlagValue(
40+
const std::vector<std::string> &args,
41+
const std::string &key)
42+
{
43+
for (size_t i = 0; i + 1 < args.size(); ++i)
44+
{
45+
if (args[i] == key)
46+
return args[i + 1];
47+
}
48+
return {};
49+
}
50+
51+
bool MigratorCLI::hasFlag(
52+
const std::vector<std::string> &args,
53+
const std::string &key)
54+
{
55+
for (const auto &a : args)
56+
{
57+
if (a == key)
58+
return true;
59+
}
60+
return false;
61+
}
62+
63+
std::string MigratorCLI::parseDir(const std::vector<std::string> &args)
64+
{
65+
std::string v = getFlagValue(args, "--dir");
66+
if (!v.empty())
67+
return v;
68+
69+
for (const auto &a : args)
70+
{
71+
const std::string p = "--dir=";
72+
if (a.rfind(p, 0) == 0)
73+
{
74+
std::string vv = a.substr(p.size());
75+
if (!vv.empty())
76+
return vv;
77+
}
78+
}
79+
80+
return "migrations";
81+
}
82+
83+
int MigratorCLI::parseStepsOrThrow(const std::vector<std::string> &args)
84+
{
85+
std::string steps_s = getFlagValue(args, "--steps");
86+
if (steps_s.empty())
87+
throw std::runtime_error("rollback requires --steps <n>");
88+
89+
int steps = 0;
90+
try
91+
{
92+
steps = std::stoi(steps_s);
93+
}
94+
catch (...)
95+
{
96+
throw std::runtime_error("invalid --steps value (must be an integer)");
97+
}
98+
99+
if (steps <= 0)
100+
throw std::runtime_error("--steps must be >= 1");
101+
102+
return steps;
103+
}
104+
105+
void MigratorCLI::validateOrThrow(const Options &opt)
106+
{
107+
if (opt.help)
108+
return;
109+
110+
if (opt.host.empty() || opt.user.empty() || opt.db.empty())
111+
throw std::runtime_error("missing required args: <host> <user> <pass> <db> <command>");
112+
113+
if (opt.command != "migrate" && opt.command != "rollback" && opt.command != "status")
114+
throw std::runtime_error("unknown command: " + opt.command);
115+
116+
if (opt.command == "rollback" && opt.steps <= 0)
117+
throw std::runtime_error("rollback requires --steps <n>");
118+
119+
if (opt.migrationsDir.empty())
120+
throw std::runtime_error("migrations dir is empty (use --dir <path>)");
121+
}
122+
123+
MigratorCLI::Options MigratorCLI::parseArgsOrThrow(int argc, char **argv)
124+
{
125+
Options opt;
126+
127+
std::vector<std::string> all;
128+
all.reserve(static_cast<size_t>(argc));
129+
for (int i = 0; i < argc; ++i)
130+
all.emplace_back(argv[i]);
131+
132+
if (argc <= 1 || hasFlag(all, "-h") || hasFlag(all, "--help"))
133+
{
134+
opt.help = true;
135+
return opt;
136+
}
137+
138+
if (argc < 6)
139+
throw std::runtime_error("not enough arguments");
140+
141+
opt.host = argv[1];
142+
opt.user = argv[2];
143+
opt.pass = argv[3];
144+
opt.db = argv[4];
145+
opt.command = argv[5];
146+
147+
std::vector<std::string> extra;
148+
for (int i = 6; i < argc; ++i)
149+
extra.emplace_back(argv[i]);
150+
151+
opt.migrationsDir = parseDir(extra);
152+
153+
if (opt.command == "rollback")
154+
opt.steps = parseStepsOrThrow(extra);
155+
156+
validateOrThrow(opt);
157+
return opt;
158+
}
159+
160+
int MigratorCLI::run(int argc, char **argv)
161+
{
162+
try
163+
{
164+
Options opt = parseArgsOrThrow(argc, argv);
165+
166+
if (opt.help)
167+
{
168+
printUsage(argv[0]);
169+
return 0;
170+
}
171+
172+
vix::db::ConnectionPtr conn;
173+
std::unique_ptr<vix::db::FileMigrationsRunner> runner;
174+
175+
#if VIX_DB_HAS_MYSQL
176+
{
177+
auto factory = vix::db::make_mysql_factory(opt.host, opt.user, opt.pass, opt.db);
178+
conn = factory();
179+
runner = std::make_unique<vix::db::FileMigrationsRunner>(*conn, opt.migrationsDir);
180+
}
181+
#elif VIX_DB_HAS_SQLITE
182+
{
183+
auto factory = vix::db::make_sqlite_factory(opt.db);
184+
conn = factory();
185+
runner = std::make_unique<vix::db::FileMigrationsRunner>(*conn, opt.migrationsDir);
186+
}
187+
#else
188+
std::cerr << "[ERR] vix_db_migrator built without DB drivers.\n"
189+
<< "Enable one with:\n"
190+
<< " -DVIX_DB_HAS_MYSQL=1 (or add SQLite support)\n";
191+
return 1;
192+
#endif
193+
194+
if (opt.command == "migrate")
195+
{
196+
runner->applyAll();
197+
std::cout << "[OK] migrations applied\n";
198+
return 0;
199+
}
200+
201+
if (opt.command == "rollback")
202+
{
203+
runner->rollback(opt.steps);
204+
std::cout << "[OK] rollback " << opt.steps << " step(s)\n";
205+
return 0;
206+
}
207+
208+
if (opt.command == "status")
209+
{
210+
std::cout << "[OK] migrations dir: " << opt.migrationsDir << "\n";
211+
std::cout << "Tip: implement FileMigrationsRunner::status() to show applied vs pending.\n";
212+
return 0;
213+
}
214+
215+
printUsage(argv[0]);
216+
return 1;
217+
}
218+
catch (const std::exception &e)
219+
{
220+
std::cerr << "[ERR] " << e.what() << "\n";
221+
std::cerr << "Tip: run with --help\n";
222+
return 1;
223+
}
224+
}
225+
226+
} // namespace vix::db::tools

tools/migrator/MigratorCLI.hpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
*
3+
* @file MigratorCLI.hpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2025, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*/
13+
#ifndef VIX_DB_MIGRATOR_CLI_HPP
14+
#define VIX_DB_MIGRATOR_CLI_HPP
15+
16+
#include <string>
17+
#include <vector>
18+
19+
namespace vix::db::tools
20+
{
21+
class MigratorCLI
22+
{
23+
public:
24+
struct Options
25+
{
26+
std::string host;
27+
std::string user;
28+
std::string pass;
29+
std::string db;
30+
31+
std::string command; // migrate | rollback | status
32+
std::string migrationsDir = "migrations";
33+
34+
int steps = 0; // rollback steps
35+
bool help = false;
36+
};
37+
38+
static int run(int argc, char **argv);
39+
40+
private:
41+
static void printUsage(const char *prog);
42+
43+
static Options parseArgsOrThrow(int argc, char **argv);
44+
45+
static std::string getFlagValue(const std::vector<std::string> &args,
46+
const std::string &key);
47+
48+
static bool hasFlag(const std::vector<std::string> &args,
49+
const std::string &key);
50+
51+
static std::string parseDir(const std::vector<std::string> &args);
52+
53+
static int parseStepsOrThrow(const std::vector<std::string> &args);
54+
55+
static void validateOrThrow(const Options &opt);
56+
};
57+
} // namespace vix::db::tools
58+
59+
#endif

tools/migrator/main.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
*
3+
* @file main.cpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2025, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*/
13+
#include "MigratorCLI.hpp"
14+
15+
int main(int argc, char **argv)
16+
{
17+
return vix::db::tools::MigratorCLI::run(argc, argv);
18+
}

0 commit comments

Comments
 (0)