vkdb
A time series database engine in C++.
Loading...
Searching...
No Matches
database.cpp
1#include <vkdb/database.h>
2#include <vkdb/interpreter.h>
3#include <vkdb/lexer.h>
4#include <vkdb/parser.h>
5
6namespace vkdb {
7
9 DatabaseName name,
10 error_callback error,
11 runtime_error_callback runtime_error
12)
13 : name_{std::move(name)}
14 , callback_{std::move(error)}
15 , runtime_callback_{std::move(runtime_error)}
16 , had_error_{false}
17 , had_runtime_error_{false} {
18 load();
19}
20
21Table& Database::createTable(const TableName& table_name) {
22 if (table_map_.contains(table_name)) {
23 throw std::runtime_error{
24 "Database::createTable(): Table '" + table_name + "' already exists."
25 };
26 }
27 table_map_.emplace(table_name, Table{path(), table_name});
28 std::filesystem::create_directories(table_map_.at(table_name).path());
29 return table_map_.at(table_name);
30}
31
32Table& Database::getTable(const TableName& table_name) {
33 if (!table_map_.contains(table_name)) {
34 throw std::runtime_error{
35 "Database::getTable(): Table '" + table_name + "' does not exist."
36 };
37 }
38 return table_map_.at(table_name);
39}
40
41void Database::dropTable(const TableName& table_name) {
42 if (!table_map_.contains(table_name)) {
43 throw std::runtime_error{
44 "Database::dropTable(): Table '" + table_name + "' does not exist."
45 };
46 }
47 std::filesystem::remove_all(table_map_.at(table_name).path());
48 table_map_.erase(table_name);
49}
50
52 std::filesystem::remove_all(path());
53}
54
55DatabaseName Database::name() const noexcept {
56 return name_;
57}
58
59FilePath Database::path() const noexcept {
60 return DATABASE_DIRECTORY / name_;
61}
62
63std::vector<TableName> Database::tables() const noexcept {
64 auto tables{std::ranges::views::keys(table_map_)};
65 return {tables.begin(), tables.end()};
66}
67
69 const std::string& source,
70 std::ostream& stream
71) noexcept {
72 Lexer lexer{source};
73 auto tokens{lexer.tokenize()};
74
75 Parser parser{tokens, [this](Token token, const std::string& message) {
76 error(token, message);
77 }};
78 auto expr{parser.parse()};
79
80 if (had_error_) {
81 return *this;
82 }
83
84 Interpreter interpreter{*this, [this](const RuntimeError& error) {
85 runtime_error(error);
86 }};
87 interpreter.interpret(expr.value(), stream);
88
89 return *this;
90}
91
93 const std::filesystem::path path,
94 std::ostream& stream
95) noexcept {
96 if (path.extension() != ".vq") {
97 std::cerr << "\033[1;32mDatabase::runFile(): File extension cannot be "
98 << path.extension() << ", must be .vq.\033[0m\n";
99 return *this;
100 }
101 std::ifstream file{path};
102 if (!file.is_open()) {
103 std::cerr << "\033[1;32mDatabase::runFile(): Unable to open file "
104 << path << ".\033[0m\n";
105 return *this;
106 }
107 std::stringstream buffer;
108 buffer << file.rdbuf();
109 run(buffer.str(), stream);
110
111 if (had_error_) {
112 exit(65);
113 }
114
115 if (had_runtime_error_) {
116 exit(70);
117 }
118
119 return *this;
120}
121
123 std::cout << "\033[1;31mwelcome to the vq repl! :)\033[0m\n";
124 std::cout << "\033[1;31m(on database '" << name_ << "')\033[0m\n";
125 std::string line;
126 while (true) {
127 std::cout << "\033[1;34m(vq) >> \033[0m";
128 if (!std::getline(std::cin, line) || line.empty()) {
129 break;
130 };
131 run(line);
132 had_error_ = false;
133 }
134 return *this;
135}
136
137void Database::error(Token token, const std::string& message) noexcept {
138 if (token.type() == TokenType::END_OF_FILE) {
139 report(token.line(), "at end", message);
140 } else {
141 report(token.line(), "at '" + token.lexeme() + "'", message);
142 }
143 had_error_ = true;
144}
145
146void Database::runtime_error(const RuntimeError& error) noexcept {
147 std::cerr << "\033[1;32m[line " << error.token().line();
148 std::cerr << "] Runtime error: " << error.message() << "\033[0m\n";
149 had_runtime_error_ = true;
150}
151
152void Database::report(
153 size_type line,
154 const std::string& where,
155 const std::string& message
156) const noexcept {
157 std::cerr << "\033[1;32m[line " << line << "] Parse error ";
158 std::cerr << where << ": " << message << "\033[0m\n";
159}
160
161void Database::load() {
162 const auto db_path{path()};
163 if (!std::filesystem::exists(db_path)) {
164 std::filesystem::create_directories(db_path);
165 return;
166 }
167
168 for (const auto& entry : std::filesystem::directory_iterator(db_path)) {
169 if (entry.is_directory()) {
170 auto table_name{entry.path().filename().string()};
171 table_map_.emplace(table_name, Table{path(), table_name});
172 }
173 }
174}
175} // namespace vkdb
Represents a database in vkdb.
Definition database.h:20
Table & getTable(const TableName &table_name)
Get the Table object.
Definition database.cpp:32
Database()=delete
Deleted default constructor.
FilePath path() const noexcept
Get the path to the database directory.
Definition database.cpp:59
std::vector< TableName > tables() const noexcept
Get the names of the tables in the database.
Definition database.cpp:63
Database & runFile(const std::filesystem::path path, std::ostream &stream=std::cout) noexcept
Run a file.
Definition database.cpp:92
void clear()
Clear the database.
Definition database.cpp:51
void dropTable(const TableName &table_name)
Drop the Table object.
Definition database.cpp:41
Database & runPrompt() noexcept
Run the prompt.
Definition database.cpp:122
DatabaseName name() const noexcept
Get the name of the database.
Definition database.cpp:55
Database & run(const std::string &source, std::ostream &stream=std::cout) noexcept
Run a source string.
Definition database.cpp:68
Table & createTable(const TableName &table_name)
Create a Table object.
Definition database.cpp:21
Interpreter for vq.
void interpret(const Expr &expr, std::ostream &stream=std::cout) const noexcept
Interpret the expression.
Lexer for vq.
Definition lexer.h:45
Parser for vq.
Definition parser.h:22
Runtime error.
Represents a table in vkdb.
Definition table.h:32
Represents a token.
Definition token.h:81
STL namespace.