22 if (value.size() > column.
width()) {
23 throw SqlError(std::format(
"value '{}' is too long for column {} (max {} characters)",
33void place(std::string& record,
const Column& column,
const std::string& value)
36 std::string padded = value;
37 padded.resize(column.
width(),
' ');
38 record.replace(column.
from, column.
width(), padded);
44 : schema_(schema), path_(std::move(path))
50 std::ifstream in(
path_);
52 throw SqlError(std::format(
"data file {} not found",
path_.filename().string()));
55 std::vector<Row> rows;
57 while (std::getline(in, line)) {
58 if (
trim(line).empty()) {
71 std::string_view text = column.from < line.size() ? line.substr(column.from, column.width()) : std::string_view{};
83 const std::vector<std::pair<std::size_t, std::string>>& newValues)
const
86 for (
const auto& [index, value] : newValues) {
89 return rewrite([&](std::string& line,
const Row& row) {
90 if (!shouldUpdate(row)) {
94 line.resize(schema_.recordLength,
' ');
96 for (
const auto& [index, value] : newValues) {
105 std::ifstream in(
path_);
107 throw SqlError(std::format(
"data file {} not found",
path_.filename().string()));
110 std::vector<std::string> kept;
111 std::size_t changed = 0;
113 while (std::getline(in, line)) {
114 if (
trim(line).empty()) {
122 kept.push_back(std::move(line));
131 std::filesystem::path temporary =
path_;
134 std::ofstream out(temporary, std::ios::trunc);
136 throw SqlError(std::format(
"cannot write {}", temporary.string()));
138 for (
const std::string& keptLine : kept) {
139 out << keptLine <<
'\n';
142 throw SqlError(std::format(
"cannot write {}", temporary.string()));
145 std::filesystem::rename(temporary,
path_);
152 if (std::filesystem::exists(
path_)) {
155 maxId = std::max(maxId, *
id);
170 std::vector<std::string> records;
171 for (
const Row& values : rows) {
173 throw SqlError(std::format(
"table {} has {} columns, got {} values",
177 for (std::size_t i = 0; i < values.size(); ++i) {
180 records.push_back(std::move(record));
184 bool needsNewline =
false;
185 if (std::ifstream existing(
path_, std::ios::binary | std::ios::ate); existing && existing.tellg() > 0) {
186 existing.seekg(-1, std::ios::end);
187 needsNewline = existing.get() !=
'\n';
190 std::ofstream out(
path_, std::ios::app);
192 throw SqlError(std::format(
"cannot write {}",
path_.string()));
197 for (
const std::string& record : records) {
198 out << record <<
'\n';
Reading, appending, editing and removing the rows of one table's data file.
std::vector< std::string > Row
One row of a table: one value per column, trailing spaces removed.
The SqlError exception and small string helpers used everywhere.
std::optional< long long > parseInteger(std::string_view text)
Parses a whole string as a base-10 integer.
std::string_view trimRight(std::string_view text)
Removes trailing spaces, tabs and line ends.
std::string_view trim(std::string_view text)
Removes leading and trailing spaces, tabs and line ends.
A problem with one statement: bad syntax, unknown table, value too long...
std::size_t removeRows(const std::function< bool(const Row &)> &shouldRemove) const
Removes the rows that match a test.
long long nextId() const
The ID to give the next new row.
std::size_t updateRows(const std::function< bool(const Row &)> &shouldUpdate, const std::vector< std::pair< std::size_t, std::string > > &newValues) const
Changes some columns in the rows that match a test.
std::size_t rewrite(const std::function< Change(std::string &line, const Row &row)> &decide) const
Rewrites the file through a temporary copy, line by line.
Change
What rewrite() does with one line.
@ Keep
Write the line back unchanged.
@ Update
Write the line back as decide edited it.
@ Remove
Leave the line out.
std::filesystem::path path_
The data file.
void append(const Row &values) const
Adds one row at the end of the file.
const TableSchema & schema_
The table's definition.
std::vector< Row > readRows() const
Reads every row of the file.
Row splitLine(std::string_view line) const
Cuts one line of the file into its column values.
void appendRows(const std::vector< Row > &rows) const
Adds several rows at the end of the file, in one write.
TableFile(const TableSchema &schema, std::filesystem::path path)
Prepares access to one data file.
void place(std::string &record, const Column &column, const std::string &value)
Writes a value into its column's characters of a row, padded with spaces to the column width.
void checkFits(const Column &column, const std::string &value)
Checks that a value fits in its column.
One column of a table: the characters it occupies in every fixed-width row.
std::size_t width() const
Number of characters the column occupies.
std::size_t from
First character of the column in a row, counted from 0.
std::string name
Column name, e.g. NOME.
The definition of one table: its name, its columns, and the length of a row.
std::string name
Table name, e.g. EMPLOY.
std::size_t recordLength
Length of a full row, in characters.
std::vector< Column > columns
Columns in file order.