Skip to content

Commit

Permalink
Iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
bgs99 committed Jun 8, 2024
1 parent 61be781 commit 5fd16d7
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 60 deletions.
3 changes: 2 additions & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ Checks:
- concurrency-*
- cert-*
- bugprone-*
- -misc-include-cleaner # not reliable
- -misc-include-cleaner # not reliable
- -llvm-header-guard # #pragma once
- -llvm-include-order # managed by clang-format
- -modernize-use-trailing-return-type # TODO
- -misc-no-recursion # simplifies code
- -cert-dcl21-cpp # conflicts with not specifying return as const

CheckOptions:
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
Expand Down
63 changes: 63 additions & 0 deletions include/podrm/sqlite/cursor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once

#include <podrm/sqlite/detail/cursor.hpp>

#include <cassert>
#include <cstddef>
#include <functional>
#include <iterator>
#include <utility>

namespace podrm::sqlite {

template <typename T> class Cursor {
public:
class Iterator;
class Sentinel {};

Iterator begin() { return Iterator{this->impl}; }
Sentinel end() { return Sentinel{}; }

private:
detail::Cursor impl;

explicit Cursor(detail::Cursor impl) : impl(std::move(impl)) {}

friend class Database;
};

template <typename T> class Cursor<T>::Iterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T *;
using reference = T &;

T operator*() const {
T result;
assert(this->cursor.get().extract(&result));
return result;
}

Iterator &operator++() {
this->cursor.get().nextRow();

return *this;
}

Iterator operator++(int) { return ++(*this); }

friend bool operator==(const Iterator &lhs, const Sentinel /*sentinel*/) {
return !lhs.cursor.get().valid();
}

private:
std::reference_wrapper<detail::Cursor> cursor;

explicit Iterator(detail::Cursor &cursor) : cursor(cursor) {}

friend class Cursor<T>;
};

} // namespace podrm::sqlite
7 changes: 7 additions & 0 deletions include/podrm/sqlite/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <podrm/api.hpp>
#include <podrm/primary_key.hpp>
#include <podrm/reflection.hpp>
#include <podrm/sqlite/cursor.hpp>
#include <podrm/sqlite/detail/connection.hpp>

#include <filesystem>
Expand Down Expand Up @@ -61,6 +62,12 @@ class Database {
this->connection.update(DatabaseEntityDescription<Entity>, &entity);
}

template <DatabaseEntity Entity> Cursor<Entity> iterate() {
return Cursor<Entity>{
this->connection.iterate(DatabaseEntityDescription<Entity>),
};
}

private:
detail::Connection connection;

Expand Down
3 changes: 3 additions & 0 deletions include/podrm/sqlite/detail/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <podrm/api.hpp>
#include <podrm/reflection.hpp>
#include <podrm/span.hpp>
#include <podrm/sqlite/detail/cursor.hpp>
#include <podrm/sqlite/detail/result.hpp>

#include <cstdint>
Expand Down Expand Up @@ -41,6 +42,8 @@ class Connection {

void update(EntityDescription description, const void *entity);

Cursor iterate(EntityDescription description);

private:
std::unique_ptr<sqlite3, int (*)(sqlite3 *)> connection;

Expand Down
26 changes: 26 additions & 0 deletions include/podrm/sqlite/detail/cursor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <podrm/reflection.hpp>
#include <podrm/span.hpp>
#include <podrm/sqlite/detail/result.hpp>

namespace podrm::sqlite::detail {

class Cursor {
public:
Cursor(Result result, span<const FieldDescription> description);

/// @param[out] data data to be initialized
[[nodiscard]] bool extract(void *data) const;

bool nextRow();

[[nodiscard]] bool valid() const;

private:
Result result;

span<const FieldDescription> description;
};

} // namespace podrm::sqlite::detail
2 changes: 2 additions & 0 deletions include/podrm/sqlite/detail/result.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class Result {

bool nextRow();

[[nodiscard]] bool valid() const;

[[nodiscard]] int getColumnCount() const { return this->columnCount; }

private:
Expand Down
3 changes: 2 additions & 1 deletion lib/sqlite/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
find_package(SQLite3 REQUIRED)

add_library(podrm-sqlite STATIC)
target_sources(podrm-sqlite PRIVATE connection.cpp entry.cpp result.cpp row.cpp)
target_sources(podrm-sqlite PRIVATE connection.cpp cursor.cpp entry.cpp
result.cpp row.cpp)
target_link_libraries(
podrm-sqlite
PUBLIC podrm-reflection
Expand Down
74 changes: 16 additions & 58 deletions lib/sqlite/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <podrm/reflection.hpp>
#include <podrm/span.hpp>
#include <podrm/sqlite/detail/connection.hpp>
#include <podrm/sqlite/detail/cursor.hpp>
#include <podrm/sqlite/detail/result.hpp>
#include <podrm/sqlite/detail/row.hpp>

Expand Down Expand Up @@ -232,51 +233,6 @@ std::vector<AsImage> intoArgs(const FieldDescription description,
description.field);
}

void init(const FieldDescription description, const Row row, int &currentColumn,
void *field) {
const auto initPrimitive = [field, row, &currentColumn](
const PrimitiveFieldDescription description) {
switch (description.imageType) {
case ImageType::Int:
description.fromImage(row.get(currentColumn).bigint(), field);
++currentColumn;
return;
case ImageType::Uint:
description.fromImage(
static_cast<std::uint64_t>(row.get(currentColumn).bigint()), field);
++currentColumn;
return;
case ImageType::String:
description.fromImage(row.get(currentColumn).text(), field);
++currentColumn;
return;
case ImageType::Float:
description.fromImage(row.get(currentColumn).real(), field);
++currentColumn;
return;
case ImageType::Bool:
description.fromImage(row.get(currentColumn).boolean(), field);
++currentColumn;
return;
case ImageType::Bytes:
description.fromImage(row.get(currentColumn).bytes(), field);
++currentColumn;
return;
}
assert(false);
};

const auto initComposite = [field, row, &currentColumn](
const CompositeFieldDescription description) {
for (const FieldDescription fieldDescr : description.fields) {
init(fieldDescr, row, currentColumn, fieldDescr.memberPtr(field));
}
};

std::visit(podrm::detail::MultiLambda{initPrimitive, initComposite},
description.field);
}

} // namespace

Connection::Connection(sqlite3 &connection)
Expand Down Expand Up @@ -401,20 +357,12 @@ bool Connection::find(const EntityDescription &description, const AsImage &key,
fmt::format("SELECT * FROM '{}' WHERE {} = ?", description.name,
description.fields[description.primaryKey].name);

const Result query =
this->query(queryStr, podrm::span<const AsImage, 1>{&key, 1});
std::optional<Row> row = query.getRow();
if (!row.has_value()) {
return false;
}

int currentColumn = 0;
for (const FieldDescription description : description.fields) {
init(description, row.value(), currentColumn,
description.memberPtr(result));
}
const Cursor cursor = Cursor{
this->query(queryStr, podrm::span<const AsImage, 1>{&key, 1}),
description.fields,
};

return true;
return cursor.extract(result);
}

void Connection::erase(const EntityDescription description,
Expand Down Expand Up @@ -464,4 +412,14 @@ void Connection::update(const EntityDescription description,
}
}

Cursor Connection::iterate(const EntityDescription description) {
const std::string queryStr =
fmt::format("SELECT * FROM '{}'", description.name);

return Cursor{
this->query(queryStr),
description.fields,
};
}

} // namespace podrm::sqlite::detail
89 changes: 89 additions & 0 deletions lib/sqlite/cursor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "../detail/multilambda.hpp"

#include <podrm/reflection.hpp>
#include <podrm/span.hpp>
#include <podrm/sqlite/detail/cursor.hpp>
#include <podrm/sqlite/detail/result.hpp>
#include <podrm/sqlite/detail/row.hpp>

#include <cassert>
#include <cstdint>
#include <optional>
#include <utility>
#include <variant>

namespace podrm::sqlite::detail {

namespace {

void init(const FieldDescription description, const Row row, int &currentColumn,
void *field) {
const auto initPrimitive = [field, row, &currentColumn](
const PrimitiveFieldDescription description) {
switch (description.imageType) {
case ImageType::Int:
description.fromImage(row.get(currentColumn).bigint(), field);
++currentColumn;
return;
case ImageType::Uint:
description.fromImage(
static_cast<std::uint64_t>(row.get(currentColumn).bigint()), field);
++currentColumn;
return;
case ImageType::String:
description.fromImage(row.get(currentColumn).text(), field);
++currentColumn;
return;
case ImageType::Float:
description.fromImage(row.get(currentColumn).real(), field);
++currentColumn;
return;
case ImageType::Bool:
description.fromImage(row.get(currentColumn).boolean(), field);
++currentColumn;
return;
case ImageType::Bytes:
description.fromImage(row.get(currentColumn).bytes(), field);
++currentColumn;
return;
}
assert(false);
};

const auto initComposite = [field, row, &currentColumn](
const CompositeFieldDescription description) {
for (const FieldDescription fieldDescr : description.fields) {
init(fieldDescr, row, currentColumn, fieldDescr.memberPtr(field));
}
};

std::visit(podrm::detail::MultiLambda{initPrimitive, initComposite},
description.field);
}

} // namespace

Cursor::Cursor(Result result, const span<const FieldDescription> description)
: result(std::move(result)), description(description) {}

bool Cursor::extract(void *data) const {
std::optional<Row> row = this->result.getRow();
if (!row.has_value()) {
return false;
}

int currentColumn = 0;
for (const FieldDescription field : description) {
init(field, row.value(), currentColumn, field.memberPtr(data));
}

return true;
}

bool Cursor::nextRow() { return this->result.nextRow(); }

bool Cursor::valid() const {
return this->result.valid();
}

} // namespace podrm::sqlite::detail
3 changes: 3 additions & 0 deletions lib/sqlite/result.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <podrm/sqlite/detail/result.hpp>

#include <cassert>
#include <optional>
#include <stdexcept>
#include <utility>

Expand Down Expand Up @@ -32,4 +33,6 @@ bool Result::nextRow() {
return true;
}

bool Result::valid() const { return this->statement.has_value(); }

} // namespace podrm::sqlite::detail
Loading

0 comments on commit 5fd16d7

Please sign in to comment.