Skip to content

Commit

Permalink
find operation
Browse files Browse the repository at this point in the history
  • Loading branch information
bgs99 committed Jun 3, 2024
1 parent 5e18476 commit c84070e
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 33 deletions.
8 changes: 6 additions & 2 deletions include/podrm/detail/span.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <cstddef>

#ifdef PFR_ORM_USE_GSL_SPAN
#include <gsl/span>
#include <gsl/span_ext>
Expand All @@ -10,9 +12,11 @@
namespace podrm::detail {

#ifdef PFR_ORM_USE_GSL_SPAN
template <typename T> using span = gsl::span<T>;
template <typename T, std::size_t Extent = gsl::dynamic_extent>
using span = gsl::span<T, Extent>;
#else
template <typename T> using span = std::span<T>;
template <typename T, std::size_t Extent = std::dynamic_extent>
using span = std::span<T, Extent>;
#endif

} // namespace podrm::detail
4 changes: 4 additions & 0 deletions include/podrm/sqlite/detail/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ bool exists(Connection &connection, const EntityDescription &entity);
void persist(Connection &connection, const EntityDescription &description,
void *entity);

/// @param[out] result pointer to the result structure, filled if found
bool find(Connection &connection, const EntityDescription &description,
Value key, void *result);

} // namespace podrm::sqlite::detail
15 changes: 15 additions & 0 deletions include/podrm/sqlite/operations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <podrm/sqlite/detail/operations.hpp>
#include <podrm/sqlite/utils.hpp>

#include <cstdint>
#include <optional>

namespace podrm::sqlite {

template <DatabaseEntity T> void createTable(Connection &connection) {
Expand All @@ -20,4 +23,16 @@ void persist(Connection &connection, Entity &entity) {
&entity);
}

/// @todo get key type from entity description
template <DatabaseEntity Entity>
std::optional<Entity> find(Connection &connection, const std::int64_t key) {
Entity result;
if (!detail::find(connection, DatabaseEntityDescription<Entity>, key,
&result)) {
return std::nullopt;
}

return result;
}

} // namespace podrm::sqlite
32 changes: 24 additions & 8 deletions include/podrm/sqlite/utils.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "podrm/detail/span.hpp"
#include <podrm/detail/span.hpp>

#include <cstddef>
#include <cstdint>
Expand All @@ -13,9 +13,31 @@

struct sqlite3;
struct sqlite3_stmt;
struct sqlite3_value;

namespace podrm::sqlite {

class Entry {
public:
/// @throws InvalidRowError if the column is outside of the range
[[nodiscard]] std::string_view text() const;

/// @throws InvalidRowError if the column is outside of the range
[[nodiscard]] std::int64_t bigint() const;

/// @throws InvalidRowError if the column is outside of the range
[[nodiscard]] bool boolean() const;

private:
sqlite3_stmt *statement;

int column;

friend class Row;

explicit Entry(sqlite3_stmt *statement, int column);
};

class Row {
public:
class InvalidRowError : public std::out_of_range {
Expand All @@ -26,13 +48,7 @@ class Row {
[[nodiscard]] int getColumnCount() const { return this->columnCount; }

/// @throws InvalidRowError if the column is outside of the range
[[nodiscard]] std::string_view text(int column) const;

/// @throws InvalidRowError if the column is outside of the range
[[nodiscard]] std::int64_t bigint(int column) const;

/// @throws InvalidRowError if the column is outside of the range
[[nodiscard]] bool boolean(int column) const;
[[nodiscard]] Entry get(int column) const;

private:
sqlite3_stmt *statement;
Expand Down
55 changes: 54 additions & 1 deletion lib/sqlite/operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

#include <podrm/api.hpp>
#include <podrm/definitions.hpp>
#include <podrm/detail/span.hpp>
#include <podrm/sqlite/detail/operations.hpp>
#include <podrm/sqlite/utils.hpp>

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -119,6 +121,35 @@ std::vector<Value> intoArgs(const FieldDescription description, void *field) {
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.nativeType) {
case NativeType::BigInt:
*static_cast<std::int64_t *>(field) = row.get(currentColumn).bigint();
++currentColumn;
return;
case NativeType::String:
*static_cast<std::string *>(field) =
static_cast<std::string>(row.get(currentColumn).text());
++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

void createTable(Connection &connection, const EntityDescription &entity) {
Expand All @@ -140,7 +171,7 @@ bool exists(Connection &connection, const EntityDescription &entity) {
const Result result = connection.query(
fmt::format("SELECT EXISTS(SELECT 1 FROM '{}')", entity.name));
// NOLINTNEXTLINE(bugprone-unchecked-optional-access): fixed query
return result.getRow().value().boolean(0);
return result.getRow().value().get(0).boolean();
}

void persist(Connection &connection, const EntityDescription &description,
Expand Down Expand Up @@ -168,4 +199,26 @@ void persist(Connection &connection, const EntityDescription &description,
connection.execute(fmt::to_string(buf), values);
}

bool find(Connection &connection, const EntityDescription &description,
const Value key, void *result) {
const std::string queryStr =
fmt::format("SELECT * FROM '{}' WHERE {} = ?", description.name,
description.fields[description.primaryKey].name);

Result query =
connection.query(queryStr, podrm::detail::span<const Value, 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));
}

return true;
}

} // namespace podrm::sqlite::detail
28 changes: 14 additions & 14 deletions lib/sqlite/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,31 +61,31 @@ void bindArg(const Statement &statement, const int pos, const Value value) {

} // namespace

std::string_view Row::text(const int column) const {
if (column < 0 || column > this->columnCount) {
throw InvalidRowError{
fmt::format("Column {} is out of range, result contains {} columns",
column, this->columnCount)};
}

std::string_view Entry::text() const {
// Required and safe
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast):
return reinterpret_cast<const char *>(
sqlite3_column_text(this->statement, column));
sqlite3_column_text(this->statement, this->column));
}

[[nodiscard]] std::int64_t Row::bigint(int column) const {
std::int64_t Entry::bigint() const {

return sqlite3_column_int64(this->statement, this->column);
}

bool Entry::boolean() const { return this->bigint() != 0; }

Entry::Entry(sqlite3_stmt *const statement, const int column)
: statement(statement), column(column) {}

Entry Row::get(const int column) const {
if (column < 0 || column > this->columnCount) {
throw InvalidRowError{
fmt::format("Column {} is out of range, result contains {} columns",
column, this->columnCount)};
}

return sqlite3_column_int64(this->statement, column);
}

[[nodiscard]] bool Row::boolean(int column) const {
return this->bigint(column) != 0;
return Entry{this->statement, column};
}

Result::Result(Result::Statement statement) : statement(std::move(statement)) {
Expand Down
2 changes: 1 addition & 1 deletion test/comparisons.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "podrm/definitions.hpp"
#include <podrm/definitions.hpp>

#include <cstddef>

Expand Down
37 changes: 30 additions & 7 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

#include <podrm/api.hpp>
#include <podrm/definitions.hpp>
#include <podrm/detail/span.hpp>
#include <podrm/sqlite/operations.hpp>
#include <podrm/sqlite/utils.hpp>

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <optional>
#include <string>

#include <fmt/core.h>
Expand All @@ -33,23 +36,43 @@ constexpr auto podrm::EntityRegistration<Person> =

static_assert(podrm::DatabaseEntity<Person>);

int main() {
int main(const int argc, const char **argv) {
podrm::detail::span<const char *const> args{
argv,
static_cast<std::size_t>(argc),
};

try {
orm::Connection conn = orm::Connection::inMemory("test");
orm::Connection conn = args.size() <= 1 ? orm::Connection::inMemory("test")
: orm::Connection::inFile(args[1]);

orm::createTable<Person>(conn);

assert(!orm::exists<Person>(conn));

Person person{
.id = 42,
.name = "Alex",
};
{
std::optional<Person> person = orm::find<Person>(conn, 42);
assert(!person.has_value());
}

orm::persist(conn, person);
{
Person person{
.id = 42,
.name = "Alex",
};

orm::persist(conn, person);
}

assert(orm::exists<Person>(conn));

{
std::optional<Person> person = orm::find<Person>(conn, 42);
assert(person.has_value());
assert(person->id == 42);
assert(person->name == "Alex");
}

return 0;
} catch (const std::exception &ex) {
fmt::print("{}\n", ex.what());
Expand Down

0 comments on commit c84070e

Please sign in to comment.