Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
52e1bff
Forward QJsonParseError when parsing raw JSON data
oblivioncth Sep 15, 2025
ca74c84
Improve StringLiteral interface
oblivioncth Sep 18, 2025
69acfa9
Fix for Doxygen 1.13
oblivioncth Sep 18, 2025
30ea751
Fix StringLiteral operator+() for characters
oblivioncth Sep 19, 2025
63caf8c
Completely fix StringLiteral operator+()
oblivioncth Sep 19, 2025
2907306
Fix QX_FOR_EACH() maximum depth
oblivioncth Sep 23, 2025
69c2f6e
Add QX_EVAL_EACH(). Fixed arg, varadic macro functions
oblivioncth Sep 23, 2025
ff66e6e
Fix json_override_convertible doc
oblivioncth Sep 27, 2025
99484ee
Add always_false helper
oblivioncth Sep 29, 2025
76c6809
Add SQL module
oblivioncth Sep 12, 2025
7c4bdd9
Bump minimum Doxygen version
oblivioncth Sep 29, 2025
0c72ef5
Merge pull request #157 from oblivioncth/feature/sql
oblivioncth Sep 29, 2025
cb3e859
Make QxPrivate consistently start with '_'
oblivioncth Sep 29, 2025
a316983
Add unwrap
oblivioncth Sep 29, 2025
59b2924
Fix handling for std::optional in SQL module
oblivioncth Sep 29, 2025
e50909a
Bump
oblivioncth Sep 29, 2025
b25b127
Fix inner SQL struct
oblivioncth Oct 1, 2025
91a5a8d
Add QX_SQL_STRUCT_OUTSIDE_FRIEND()
oblivioncth Oct 1, 2025
7137735
Add support for constructing Error out of a variant of error types
oblivioncth Oct 2, 2025
196c85b
Make SQL query struct call from main macros separate
oblivioncth Oct 3, 2025
2f25f2b
Tweak SQL query struct macro interfaces
oblivioncth Oct 3, 2025
c62922d
Allow retrieval of single SQL field without struct
oblivioncth Oct 4, 2025
fd40a91
Add function equivalents of SQL literal operators
oblivioncth Oct 5, 2025
f511d79
Add single row result version of SqlDqlQuery::execute()
oblivioncth Oct 5, 2025
e377f19
SQL: Improve usability of ORDER BY
oblivioncth Oct 5, 2025
f3b51a7
Add type-based version of SqlDmlQuery::UPDATE()
oblivioncth Oct 5, 2025
9820e29
Add range form of AbstractSqlQuery::IN()
oblivioncth Oct 5, 2025
e7eb38b
Add SqlString::isEmpty()
oblivioncth Oct 7, 2025
734d858
Add LIKE, ILIKE, and ESCAPE SQL inlines
oblivioncth Oct 7, 2025
1c9ed72
At concat operators for SQL inlines
oblivioncth Oct 7, 2025
57cd3cc
Add IN SQL inline
oblivioncth Oct 7, 2025
08b70e1
Add operator!() to SQL inlnine
oblivioncth Oct 7, 2025
e21de03
Add range ctor for SQL inline
oblivioncth Oct 7, 2025
51bc3f8
Fix doc for SqlString and SQL inline operators
oblivioncth Oct 7, 2025
e25b53f
More SQL doc fixes
oblivioncth Oct 7, 2025
da7ff78
Improve sql_stringable concept
oblivioncth Oct 7, 2025
6808455
Add QUuid ctor for SqlString
oblivioncth Oct 7, 2025
8512f10
Add sub-query ctor for SQL inline IN
oblivioncth Oct 7, 2025
74ac147
Allow SqlQuery construction without database
oblivioncth Oct 7, 2025
26446ad
Fix SQL inline list ctor
oblivioncth Oct 7, 2025
623cde5
Fix SqlResult
oblivioncth Oct 7, 2025
667f120
Fix SQL inline range ctor
oblivioncth Oct 7, 2025
3a008d1
Fix SQL IN()
oblivioncth Oct 7, 2025
a6e35a8
Auto close DB connection on thread finish instead of deletion
oblivioncth Oct 8, 2025
e3d6f81
SQL: Fix schema report field acquisition validity check
oblivioncth Oct 8, 2025
25934bd
Fix out-of-order initialization of IoOpReport dependent vars
oblivioncth Oct 9, 2025
2fe1390
Remove unused SQL database static variable
oblivioncth Oct 9, 2025
3d9f0fa
Improve SqlDqlQuery execute() overloads.
oblivioncth Oct 9, 2025
854ab57
Have SqlResult<T> start before first result, like QSqlResult
oblivioncth Oct 9, 2025
157771e
Add SqlDqlQuery::appendExecute()
oblivioncth Oct 9, 2025
42deed2
SQL Inlines workaround for GCC ICE
oblivioncth Oct 9, 2025
35191e7
SQL: Fix parenthenses based keyword creation
oblivioncth Oct 10, 2025
f6d47a2
Fix qCritical() string argument type
oblivioncth Oct 10, 2025
41c42a0
Disconnect thread monitoring slot in SqlDatabase in dtor
oblivioncth Oct 12, 2025
97b43da
Switch to lambda for concept `error_type ` impl
oblivioncth Oct 12, 2025
5e7ca92
Add small note to SQL docs
oblivioncth Oct 13, 2025
8623e6a
Add SQL module as highlight
oblivioncth Oct 13, 2025
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.23.0...3.31.0)
# avoided and only used for hotfixes. DON'T USE TRAILING
# ZEROS IN VERSIONS
project(Qx
VERSION 0.6.3
VERSION 0.7
LANGUAGES CXX
DESCRIPTION "Qt Extensions Library"
)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Detailed documentation of this library, facilitated by Doxygen, is available at:

- [Bindable Properties](https://oblivioncth.github.io/Qx/properties.html)
- [Declarative JSON](https://oblivioncth.github.io/Qx/declarativejson.html)
- [Declarative SQL](https://oblivioncth.github.io/Qx/declarativesql.html)
- [Qx::ApplicationLogger](https://oblivioncth.github.io/Qx/classQx_1_1ApplicationLogger.html)
- [Qx::AsyncDownloadManager](https://oblivioncth.github.io/Qx/classQx_1_1AsyncDownloadManager.html)/[Qx::SyncDownloadManager](https://oblivioncth.github.io/Qx/classQx_1_1SyncDownloadManager.html)
- [Qx::Base85](https://oblivioncth.github.io/Qx/classQx_1_1Base85.html)
Expand Down
5 changes: 4 additions & 1 deletion doc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ set(DOXYGEN_PREDEFINED

set(DOXYGEN_EXCLUDE_SYMBOLS
"_QxPrivate"
"__QX*"
)

include(cmake/SqlMacros.cmake)

# Setup documentation
ob_standard_documentation(${DOC_TARGET_NAME}
DOXY_VER 1.9.4
DOXY_VER 1.12.0
PROJ_NAME "${PROJECT_NAME}"
QT_MODULES
qtconcurrent
Expand Down
52 changes: 52 additions & 0 deletions doc/cmake/SqlMacros.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Forwhaetver reason, putting these in DOXYGEN_EXPAND_AS_DEFINED does not work, possibly because
# there are nested macros, so we have to define all of the macros used to create symobls that need
# documentation in the SQL module here in a way that allows Doxygen to recognize said symbols.
# The function definition isn't needed, just the declaration.
#
# NOTE: @ seems not to work here, so we need to use \\ for doxygen commands instead (\ itself escaped)

list(APPEND DOXYGEN_PREDEFINED
# Queries
"__QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG_X(keyword, method)=\
/*! Adds a `keyword` clause to the query and returns a reference to the query. */ \
auto& method();"
"__QX_SQL_QUERY_ADD_KEYWORD_ZERO_ARG(keyword)=\
/*! Adds a `keyword` clause to the query and returns a reference to the query. */ \
auto& keyword();"
"__QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_X(keyword, method)=\
/*! Adds a `keyword` clause to the query using \\a fs and returns a reference to the query. */ \
template<sql_stringable First> auto& method(First&& fs);"
"__QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_PAREN_X(keyword, method)=\
/*! Adds a `keyword` clause to the query using \\a fs and returns a reference to the query. */ \
template<sql_stringable First> auto& method(First&& fs);"
"__QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG(keyword)=\
/*! Adds a `keyword` clause to the query using \\a fs and returns a reference to the query. */ \
template<sql_stringable First> auto& keyword(First&& fs);"
"__QX_SQL_QUERY_ADD_KEYWORD_SINGLE_ARG_PAREN(keyword)=\
/*! Adds a `keyword` clause to the query using \\a fs and returns a reference to the query. */ \
template<sql_stringable First> auto& keyword(First&& fs);"
"__QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_X(keyword, method)=\
/*! Adds a `keyword` clause to the query using \\a fs through \\a s and returns a reference \
to the query. */ \
template<sql_stringable First, sql_stringable ...Rest> auto& method(First&& fs, Rest&&... s);"
"__QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN_X(keyword, method)=\
/*! Adds a `keyword` clause to the query using \\a fs through \\a s and returns a reference \
to the query. */ \
template<sql_stringable First, sql_stringable ...Rest> auto& method(First&& fs, Rest&&... s);"
"__QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG(keyword)=\
/*! Adds a `keyword` clause to the query using \\a fs through \\a s and returns a reference \
to the query. */ \
template<sql_stringable First, sql_stringable ...Rest> auto& keyword(First&& fs, Rest&&... s);"
"__QX_SQL_QUERY_ADD_KEYWORD_MULTI_ARG_PAREN(keyword)=\
/*! Adds a `keyword` clause to the query using \\a fs through \\a s and returns a reference \
to the query. */ \
template<sql_stringable First, sql_stringable ...Rest> auto& keyword(First&& fs, Rest&&... s);"
"__QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY_X(keyword, method)=\
/*! Adds a `keyword` clause to the query using \\a q as a sub-query and returns a reference \
to the query. */ \
auto& method(const SqlQuery& q);"
"__QX_SQL_QUERY_ADD_KEYWORD_SUB_QUERY(keyword)=\
/*! Adds a `keyword` clause to the query using \\a q as a sub-query and returns a reference \
to the query. */ \
auto& keyword(const SqlQuery& q);"
)
3 changes: 2 additions & 1 deletion doc/general/majorfeatures.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Major Features {#majorfeatures}
===============================

This page catalogues the most significant features of Qx, which generally form a complete/comprehensive system that can be evaluated independently from the rest of the library.
This page catalogues the most significant features of Qx, which generally form a complete/comprehensive system that can be evaluated independently from the rest of the library.

- @subpage properties "Bindable Properties System"
- @subpage declarativejson "Declarative JSON"
- @subpage declarativesql "Declarative SQL module"
2 changes: 1 addition & 1 deletion lib/core/include/qx/core/__private/qx-internalerror.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "qx/core/qx-abstracterror.h"

/*! @cond */
namespace QxPrivate
namespace _QxPrivate
{

// Basically a copy of GenericError for internal use only
Expand Down
42 changes: 14 additions & 28 deletions lib/core/include/qx/core/qx-abstracterror.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ class QX_CORE_EXPORT IError
static inline const QString T_NAME_DUPE = u"Error type name %1 is already claimed!"_s;
static inline const QString T_CODE_RESERVED = u"Error type code %1 is reserved!"_s;
static inline constinit QHash<quint16, const QString*> codeRegistry;
static constexpr std::array<QStringView, 8> RESERVED_NAMES{
static constexpr std::array<QStringView, 10> RESERVED_NAMES{
u"Qx::InternalError",
u"Qx::GenericError",
u"Qx::IoOpReport",
u"Qx::SystemError",
u"Qx::DownloadManagerReport",
u"Qx::DownloadOpReport",
u"Qx::JsonError",
u"QJsonParseError"
u"QJsonParseError",
u"Qx::SqlError",
u"Qx::SqlSchemaReport",
};
// TODO: If this becomes sufficiently large, move to a constexpr set (hopefully available in std by that time)

Expand Down Expand Up @@ -81,14 +83,14 @@ class QX_CORE_EXPORT IError
bool operator!=(const IError& other) const = default;
};

template<StringLiteral EName, quint16 ECode>
template<CStringLiteral EName, quint16 ECode>
class AbstractError : protected IError
{
friend class Error;
//-Class Variables----------------------------------------------------------------------------------------------------------
public:
static constexpr quint16 TYPE_CODE = ECode;
static constexpr QLatin1StringView TYPE_NAME{EName.value};
static constexpr QLatin1StringView TYPE_NAME{EName};

private:
static const bool REGISTER;
Expand Down Expand Up @@ -116,39 +118,23 @@ friend class Error;

//-Namespace Concepts-------------------------------------------------------------------------------------------------------

/* TODO: Clang 12 doesn't support the C++20 feature "Lambdas in unevaluated contexts",
* so this helper function needs to be used instead. Once moving on to at least Clang 13
* as the minimum supported version instead the lambda commented out below can be used
* instead.
*/
//template<class E>
//concept error_type = requires(E type) {
// // IIFE that ensures E is a specialization of AbstractError
// []<StringLiteral Y, quint16 Z>(AbstractError<Y, Z>&){}(type);
//};
template<class E>
concept error_type = requires(E type) {
// IIFE that ensures E is a specialization of AbstractError
[]<CStringLiteral Y, quint16 Z>(AbstractError<Y, Z>&){}(type);
};

/* Define error type registrar variable. This must be done out of line to ensure that only
* one instance of the variable exists per-error-type across an entire program. If the variable
* is defined inline, multiple versiosn of it can exist in parallel when linking via shared-libraries,
* is defined inline, multiple versions of it can exist in parallel when linking via shared-libraries,
* if those libraries are used by multiple targets in the same project. This would cause an error type
* to call registerType() multiple times.
*/
template<StringLiteral EName, quint16 ECode>
const bool AbstractError<EName, ECode>::REGISTER = registerType(TYPE_CODE, TYPE_NAME);

/*! @cond */
namespace AbstractErrorPrivate
{
template<Qx::StringLiteral Y, quint16 Z>
void aeDerived(Qx::AbstractError<Y, Z>&);
}
template<CStringLiteral EName, quint16 ECode>
const bool AbstractError<EName, ECode>::REGISTER = registerType(TYPE_CODE, TYPE_NAME);
/*! @endcond */

template<class E>
concept error_type = requires(E type) {
AbstractErrorPrivate::aeDerived(type);
};

template<class A>
concept error_adapter =
error_type<A> &&
Expand Down
42 changes: 37 additions & 5 deletions lib/core/include/qx/core/qx-error.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,39 @@ namespace QxErrorPrivate
* half the purpose of the adapters.
*/
namespace Qx { class Error; }

QX_CORE_EXPORT QTextStream& operator<<(QTextStream& ts, const Qx::Error& e);

namespace Qx
{

class Error;

// Need to define here, needed later
template<class E>
concept adapted_error = error_adaptation<E, typename QxErrorPrivate::adapter_registry<E>::adapter>;

}

/*! @cond */
namespace QxErrorPrivate
{

template <typename T>
inline constexpr bool variant_has_error_types = false;

template <typename... Types>
inline constexpr bool variant_has_error_types<std::variant<Types...>> =
((Qx::error_type<Types> || Qx::adapted_error<Types>) && ...);

}
/*! @endcond */

namespace Qx
{

template <typename V>
concept error_variant = QxErrorPrivate::variant_has_error_types<V>;

class QX_CORE_EXPORT Error
{
//-Class Variables----------------------------------------------------------------------------------------------------------
Expand All @@ -42,7 +69,7 @@ class QX_CORE_EXPORT Error

// Adapter Registry Alias
template <class K>
using AdapterRegistry = QxErrorPrivate::adapter_registry<K>;
using AdapterType = typename QxErrorPrivate::adapter_registry<K>::adapter;

public:
static constexpr quint16 TYPE_CODE = 0;
Expand Down Expand Up @@ -82,9 +109,14 @@ class QX_CORE_EXPORT Error
}
}

template<class EAble, class EAter = typename AdapterRegistry<EAble>::adapter>
requires error_adaptation<EAble, EAter>
Error(const EAble& adapted) : Error(EAter(adapted))
template<class EAble>
requires adapted_error<EAble>
Error(const EAble& adapted) : Error(AdapterType<EAble>(adapted))
{}

template<typename Errors>
requires error_variant<Errors>
Error(const Errors& e) : Error(std::visit([](auto&& arg){ return arg; }, e))
{}

//-Instance Functions------------------------------------------------------------------------------------------------------
Expand Down
25 changes: 14 additions & 11 deletions lib/core/include/qx/core/qx-json.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,11 @@ class QX_CORE_EXPORT File

class QX_CORE_EXPORT Data
{
private:
QString mDataError;

public:
Data();
Data(const QString& dataError = {});

QString string() const;
};
Expand Down Expand Up @@ -227,7 +230,7 @@ namespace QxJson
template<typename T>
struct Converter;

template<class Struct, Qx::StringLiteral member>
template<class Struct, Qx::CStringLiteral member>
struct MemberOverrideCoverter;

template<typename SelfType, typename DelayedSelfType>
Expand Down Expand Up @@ -258,7 +261,7 @@ concept json_convertible = requires(T& tValue) {
{ Converter<T>::toJson(tValue) } -> qjson_type;
};

template<class K, typename T, Qx::StringLiteral N>
template<class K, typename T, Qx::CStringLiteral N>
concept json_override_convertible = requires(T& tValue) {
{ MemberOverrideCoverter<K, N>::fromJson(tValue, QJsonValue()) } -> std::same_as<Qx::JsonError>;
{ MemberOverrideCoverter<K, N>::toJson(tValue) } -> qjson_type;
Expand Down Expand Up @@ -303,16 +306,16 @@ static inline const QString ERR_READ_DATA = u"JSON Error: Could not read JSON da
static inline const QString ERR_WRITE_FILE = u"JSON Error: Could not write JSON file."_s;

//-Structs---------------------------------------------------------------
template<Qx::StringLiteral MemberN, typename MemberT, class Struct>
template<Qx::CStringLiteral MemberN, typename MemberT, class Struct>
struct MemberMetadata
{
constexpr static Qx::StringLiteral M_NAME = MemberN;
constexpr static Qx::CStringLiteral M_NAME = MemberN;
typedef MemberT M_TYPE;
MemberT Struct::* mPtr;
};

//-Functions-------------------------------------------------------------
template <Qx::StringLiteral N, typename T, class S>
template <Qx::CStringLiteral N, typename T, class S>
constexpr MemberMetadata<N, T, S> makeMemberMetadata(T S::*memberPtr)
{
return {memberPtr};
Expand Down Expand Up @@ -374,14 +377,14 @@ constexpr auto getMemberMeta()
return QxJson::QxJsonMetaStructOutside<K, K>::memberMetadata();
}

template<class K, typename T, Qx::StringLiteral N>
template<class K, typename T, Qx::CStringLiteral N>
requires QxJson::json_override_convertible<K, T, N>
Qx::JsonError overrideParse(T& value, const QJsonValue& jv)
{
return QxJson::MemberOverrideCoverter<K, N>::fromJson(value, jv);
}

template<class K, typename T, Qx::StringLiteral N>
template<class K, typename T, Qx::CStringLiteral N>
requires QxJson::json_override_convertible<K, T, N>
auto overrideSerialize(const T& value)
{
Expand Down Expand Up @@ -462,7 +465,7 @@ struct Converter<T>
([&]{
// Meta
static constexpr auto mName = std::remove_reference<decltype(memberMeta)>::type::M_NAME;
constexpr QLatin1StringView mKey(mName.value);
constexpr QLatin1StringView mKey(mName);
using mType = typename std::remove_reference<decltype(memberMeta)>::type::M_TYPE;
auto& mRef = value.*(memberMeta.mPtr);

Expand Down Expand Up @@ -511,7 +514,7 @@ struct Converter<T>
([&]{
// Meta
static constexpr auto mName = std::remove_reference<decltype(memberMeta)>::type::M_NAME;
constexpr QLatin1StringView mKey(mName.value);
constexpr QLatin1StringView mKey(mName);
using mType = typename std::remove_reference<decltype(memberMeta)>::type::M_TYPE;
auto& mRef = value.*(memberMeta.mPtr);

Expand Down Expand Up @@ -812,7 +815,7 @@ JsonError parseJson(T& parsed, const QByteArray& data)
QJsonDocument jd = QJsonDocument::fromJson(data, &jpe);

if(jpe.error != jpe.NoError)
return JsonError(QxJsonPrivate::ERR_READ_DATA, JsonError::InvalidData).withContext(QxJson::Data());
return JsonError(QxJsonPrivate::ERR_READ_DATA, JsonError::InvalidData).withContext(QxJson::Data(jpe.errorString()));

// True parse
return parseJson(parsed, jd).withContext(QxJson::Data());
Expand Down
2 changes: 1 addition & 1 deletion lib/core/src/__private/qx-internalerror.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include "qx/core/__private/qx-internalerror.h"

/*! @cond */
namespace QxPrivate
namespace _QxPrivate
{

//===============================================================================================================
Expand Down
4 changes: 2 additions & 2 deletions lib/core/src/qx-abstracterror.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ QString IError::deriveDetails() const { return QString(); }
//-Class Variables----------------------------------------------------------------------------------------------------------
//Public:
/*!
* @var quint16 AbstractError<StringLiteral EName, quint16 ECode>::TYPE_CODE
* @var quint16 AbstractError<CStringLiteral EName, quint16 ECode>::TYPE_CODE
* The type code of the specific error type. Dictated by @a ECode.
*/

/*!
* @var quint16 AbstractError<StringLiteral EName, quint16 ECode>::TYPE_NAME
* @var quint16 AbstractError<CStringLiteral EName, quint16 ECode>::TYPE_NAME
* The type name of the specific error type. Dictated by @a EName.
*/

Expand Down
Loading