Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
445 changes: 287 additions & 158 deletions README.md

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions include/database.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

#pragma once

#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>

#include "reflection.h"
Expand All @@ -31,7 +33,6 @@
#include "queries.h"

struct sqlite3;
struct sqlite3_stmt;

namespace sqlite_reflection {
/// A wrapper of an SQLite database, enabling type-safe and compile-time CRUD operations,
Expand All @@ -53,7 +54,9 @@ namespace sqlite_reflection {
static const Database& Instance();

Database(Database const&) = delete;
void operator=(Database const&) = delete;
Database(Database&&) = delete;
Database& operator=(const Database&) = delete;
Database& operator=(Database&&) = delete;

/// Retrieves all entries of a given record from the database.
/// This corresponds to a SELECT query in the SQL syntax
Expand Down Expand Up @@ -178,8 +181,9 @@ namespace sqlite_reflection {
Delete(record, predicate);
}

/// Executes a raw SQL query. A trailing semicolon is added if needed
void Sql(const std::string& raw_sql_query) const;
/// Executes a raw SQL query. A trailing semicolon is added if needed.
/// Prefer the type-safe CRUD APIs for user-provided values.
void UnsafeSql(const std::string& raw_sql_query) const;

private:
explicit Database(const char* path);
Expand Down
11 changes: 7 additions & 4 deletions include/queries.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#pragma once

#include <string>
#include <functional>
#include <vector>

#include "reflection.h"
#include "query_predicates.h"
Expand Down Expand Up @@ -72,7 +72,8 @@ namespace sqlite_reflection {
void Execute() const;

protected:
std::vector<std::string> GetValues(void* p) const;
virtual std::vector<SqlValue> Bindings() const;
std::vector<SqlValue> GetValues(void* p) const;
};

/// A query for which direct SQL prompts are used
Expand All @@ -84,7 +85,7 @@ namespace sqlite_reflection {

protected:
std::string PrepareSql() const override;
const std::string& sql_;
std::string sql_;
};

/// A query for creating a table for a given reflectable struct. When the database
Expand All @@ -111,6 +112,7 @@ namespace sqlite_reflection {

protected:
std::string PrepareSql() const override;
std::vector<SqlValue> Bindings() const override;
const QueryPredicateBase* predicate_;
};

Expand All @@ -124,7 +126,7 @@ namespace sqlite_reflection {

protected:
std::string PrepareSql() const override;
std::string JoinedValues() const;
std::vector<SqlValue> Bindings() const override;
void* p_;
};

Expand All @@ -138,6 +140,7 @@ namespace sqlite_reflection {

protected:
std::string PrepareSql() const override;
std::vector<SqlValue> Bindings() const override;
void* p_;
};

Expand Down
49 changes: 33 additions & 16 deletions include/query_predicates.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following predicates:
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
Expand All @@ -22,24 +22,40 @@

#pragma once

#include "reflection.h"

#include <functional>
#include <string>
#include <memory>
#include <vector>

#include "reflection.h"

namespace sqlite_reflection {
class AndPredicate;
class OrPredicate;

struct REFLECTION_EXPORT SqlValue
{
SqlValue();

SqliteStorageClass storage_class;
int64_t int_value;
bool bool_value;
double real_value;
std::string text_value;
};

/// The base class of all WHERE predicates used in SQLite queries
class REFLECTION_EXPORT QueryPredicateBase
{
public:
virtual ~QueryPredicateBase() = default;

/// Returns a textual representation of the predicate, ready to be consumed by the SELECT query
/// Returns a textual representation of the predicate with placeholders for bound values
virtual std::string Evaluate() const = 0;

/// Returns values that need to be bound to the predicate placeholders
virtual std::vector<SqlValue> Bindings() const = 0;

/// Creates a clone for compounding predicates
virtual QueryPredicateBase* Clone() const = 0;

Expand All @@ -59,11 +75,12 @@ namespace sqlite_reflection {
{
public:
std::string Evaluate() const override;
std::vector<SqlValue> Bindings() const override;
QueryPredicateBase* Clone() const override;

protected:
template <typename T, typename R>
QueryPredicate(R T::* fn, R value, const std::string& symbol, std::function<std::string(void*, SqliteStorageClass)> value_retrieval)
QueryPredicate(R T::* fn, R value, const std::string& symbol, std::function<SqlValue(void*, SqliteStorageClass)> value_retrieval)
: symbol_(symbol)
{
auto record = GetRecordFromTypeId(typeid(T).name());
Expand All @@ -80,16 +97,16 @@ namespace sqlite_reflection {
template <typename T, typename R>
QueryPredicate(R T::* fn, R value, const std::string& symbol)
: QueryPredicate(fn, value, symbol, [&](void* v, SqliteStorageClass storage_class){
return GetStringForValue(v, storage_class);
return GetSqlValue(v, storage_class);
}) {}

QueryPredicate(const std::string& symbol, const std::string& member_name, const std::string& value)
QueryPredicate(const std::string& symbol, const std::string& member_name, const SqlValue& value)
: symbol_(symbol), member_name_(member_name), value_(value) {}

/// Returns a textual representation of the value used for the current query, against which the
/// struct member (defined from the pointer-to-member function) will be compared. The value needs
/// Returns the value used for the current query, against which the struct member
/// (defined from the pointer-to-member function) will be compared. The value needs
/// to be type-erased, so that the header file is not bloated with unnecessary implementation details
virtual std::string GetStringForValue(void* v, SqliteStorageClass storage_class) const;
virtual SqlValue GetSqlValue(void* v, SqliteStorageClass storage_class) const;

/// The symbol used for the comparison, for example "=" for equality
std::string symbol_;
Expand All @@ -98,16 +115,16 @@ namespace sqlite_reflection {
/// textual representation of the evaluation string
std::string member_name_;

/// The textual representation of the comparison value, used to construct the
/// textual representation of the evaluation string
std::string value_;
/// The comparison value that will be bound to the generated SQL placeholder
SqlValue value_;
};

/// A wrapper for an empty predicate, used to fetch all elements of an SQLite table
class REFLECTION_EXPORT EmptyPredicate final : public QueryPredicateBase
{
public:
std::string Evaluate() const override;
std::vector<SqlValue> Bindings() const override;
QueryPredicateBase* Clone() const override;
};

Expand Down Expand Up @@ -155,7 +172,7 @@ namespace sqlite_reflection {
template <typename T, typename R>
explicit Like(R T::* fn, R value)
: QueryPredicate(fn, value, "LIKE", [&](void* v, SqliteStorageClass storage_class){
return GetStringForValue(v, storage_class);
return GetSqlValue(v, storage_class);
}) {}

template <typename T>
Expand All @@ -167,8 +184,7 @@ namespace sqlite_reflection {
: Like(fn, std::wstring(value)) {}

protected:
std::string GetStringForValue(void* v, SqliteStorageClass storage_class) const override;
static std::string Remove(const std::string& source, const std::string& substring);
SqlValue GetSqlValue(void* v, SqliteStorageClass storage_class) const override;
};

/// A wrapper for a comparison predicate, for which the value of the
Expand Down Expand Up @@ -249,6 +265,7 @@ namespace sqlite_reflection {
{
public:
std::string Evaluate() const override;
std::vector<SqlValue> Bindings() const override;

protected:
BinaryPredicate(const QueryPredicateBase& left, const QueryPredicateBase& right, const std::string& symbol);
Expand Down
19 changes: 9 additions & 10 deletions include/reflection.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@
#ifndef REFLECTION_INTERNAL
#define REFLECTION_INTERNAL

#include <vector>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <map>
#include <string>
#include <functional>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>

#include "reflection_export.h"

#ifndef _WIN32
#include <stddef.h>
#endif

/// The storage class in an SQLite column for a given member of a struct, for which reflection is enabled
/// https://www.sqlite.org/datatype3.html
enum class REFLECTION_EXPORT SqliteStorageClass
Expand Down Expand Up @@ -105,10 +104,10 @@ template <typename T, typename R>
size_t OffsetFromStart(R T::* fn) {
const auto sf = sizeof(fn);
char bytes_f[sf];
memcpy(bytes_f, (const char*)&fn, sf);
auto len = strlen(bytes_f);
std::memcpy(bytes_f, reinterpret_cast<const char*>(&fn), sf);
size_t offset = 0;
memcpy(&offset, bytes_f, len);
const auto bytes_to_copy = sf < sizeof(offset) ? sf : sizeof(offset);
std::memcpy(&offset, bytes_f, bytes_to_copy);
return offset;
}

Expand Down
7 changes: 2 additions & 5 deletions src/database.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@
#include "database.h"

#include <stdexcept>
#include <memory>
#include <iterator>

#include "internal/string_utilities.h"
#include "queries.h"
#include "internal/sqlite3.h"
#include "queries.h"

namespace sqlite_reflection {
Database* Database::instance_ = nullptr;
Expand Down Expand Up @@ -96,7 +93,7 @@ namespace sqlite_reflection {
query.Execute();
}

void Database::Sql(const std::string& raw_sql_query) const {
void Database::UnsafeSql(const std::string& raw_sql_query) const {
SqlQuery sql(db_, raw_sql_query);
sql.Execute();
}
Expand Down
Loading
Loading