schema progress
This commit is contained in:
parent
6a5974337d
commit
f01e9ff87f
|
|
@ -29,10 +29,11 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${GCC_CLANG_COMMON_FLAGS_DEBUG}")
|
set(CMAKE_CXX_FLAGS_DEBUG "${GCC_CLANG_COMMON_FLAGS_DEBUG}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${GCC_CLANG_COMMON_FLAGS_RELEASE}")
|
set(CMAKE_CXX_FLAGS_RELEASE "${GCC_CLANG_COMMON_FLAGS_RELEASE}")
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||||
MESSAGE(STATUS "MSVC detected - Adding compiler flags")
|
message(STATUS "MSVC detected - Adding compiler flags")
|
||||||
SET(CMAKE_CXX_FLAGS "/W3 /EHsc /bigobj")
|
set(CMAKE_CXX_FLAGS "/W3 /EHsc /bigobj")
|
||||||
SET(CMAKE_CXX_FLAGS_DEBUG "/MDd /Od /Zi /D_DEBUG /DDEBUG")
|
set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Od /Zi /D_DEBUG /DDEBUG")
|
||||||
SET(CMAKE_CXX_FLAGS_RELEASE "/O1 /DNDEBUG")
|
set(CMAKE_CXX_FLAGS_RELEASE "/O1 /DNDEBUG")
|
||||||
|
add_compile_options(/Zc:preprocessor)
|
||||||
endif ()
|
endif ()
|
||||||
#if(ENABLE_COVERAGE)
|
#if(ENABLE_COVERAGE)
|
||||||
# # set compiler flags
|
# # set compiler flags
|
||||||
|
|
@ -53,5 +54,6 @@ endif ()
|
||||||
|
|
||||||
|
|
||||||
add_subdirectory(source)
|
add_subdirectory(source)
|
||||||
|
add_subdirectory(demo)
|
||||||
add_subdirectory(backends)
|
add_subdirectory(backends)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
add_executable(demo main.cpp)
|
add_executable(demo main.cpp)
|
||||||
target_link_libraries(demo PRIVATE
|
target_link_libraries(demo PRIVATE
|
||||||
matador
|
matador-core
|
||||||
|
matador-orm
|
||||||
${CMAKE_DL_LIBS}
|
${CMAKE_DL_LIBS}
|
||||||
${SQLite3_LIBRARIES}
|
${SQLite3_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
289
demo/main.cpp
289
demo/main.cpp
|
|
@ -1,13 +1,18 @@
|
||||||
#include "matador/sql/column.hpp"
|
#include "matador/sql/column.hpp"
|
||||||
#include "matador/sql/condition.hpp"
|
|
||||||
#include "matador/sql/schema.hpp"
|
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
#include "matador/sql/entity.hpp"
|
#include "matador/sql/query_macro.hpp"
|
||||||
|
|
||||||
|
#include "matador/query/condition.hpp"
|
||||||
|
|
||||||
|
#include "matador/object/object_ptr.hpp"
|
||||||
|
#include "matador/object/schema.hpp"
|
||||||
|
|
||||||
#include "matador/utils/access.hpp"
|
#include "matador/utils/access.hpp"
|
||||||
|
#include "matador/utils/default_type_traits.hpp"
|
||||||
#include "matador/utils/enum_mapper.hpp"
|
#include "matador/utils/enum_mapper.hpp"
|
||||||
|
#include "matador/utils/types.hpp"
|
||||||
|
|
||||||
#include "matador/sql/query_helper.hpp"
|
#include "matador/sql/query_macro.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -22,7 +27,7 @@ struct author {
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::utils::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::attribute( op, "first_name", first_name, 63 );
|
field::attribute( op, "first_name", first_name, 63 );
|
||||||
field::attribute( op, "last_name", last_name, 63 );
|
field::attribute( op, "last_name", last_name, 63 );
|
||||||
|
|
@ -34,13 +39,13 @@ struct author {
|
||||||
|
|
||||||
struct book {
|
struct book {
|
||||||
unsigned long id{};
|
unsigned long id{};
|
||||||
matador::sql::entity<author> book_author;
|
matador::object::object_ptr<author> book_author;
|
||||||
std::string title;
|
std::string title;
|
||||||
unsigned short published_in{};
|
unsigned short published_in{};
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::utils::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::attribute( op, "title", title, 511 );
|
field::attribute( op, "title", title, 511 );
|
||||||
field::has_one( op, "author_id", book_author, matador::utils::default_foreign_attributes );
|
field::has_one( op, "author_id", book_author, matador::utils::default_foreign_attributes );
|
||||||
|
|
@ -53,7 +58,7 @@ struct payload {
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::utils::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -73,7 +78,7 @@ struct job {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned long id{};
|
unsigned long id{};
|
||||||
matador::sql::entity<payload> payload;
|
matador::object::object_ptr<payload> payload;
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string description;
|
std::string description;
|
||||||
job_state state;
|
job_state state;
|
||||||
|
|
@ -81,7 +86,7 @@ struct job {
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process( Operator& op ) {
|
void process( Operator& op ) {
|
||||||
namespace field = matador::utils::access;
|
namespace field = matador::access;
|
||||||
field::primary_key( op, "id", id );
|
field::primary_key( op, "id", id );
|
||||||
field::belongs_to( op, "payload", payload, matador::utils::default_foreign_attributes );
|
field::belongs_to( op, "payload", payload, matador::utils::default_foreign_attributes );
|
||||||
field::attribute( op, "type", type, 511 );
|
field::attribute( op, "type", type, 511 );
|
||||||
|
|
@ -105,13 +110,10 @@ static const matador::utils::enum_mapper<job::job_mode> job_mode_enum({
|
||||||
});
|
});
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct matador::sql::data_type_traits<job::job_state, void>
|
struct matador::utils::data_type_traits<job::job_state, void> {
|
||||||
{
|
static basic_type type(const std::size_t size) { return data_type_traits<std::string>::type(size); }
|
||||||
inline static data_type_t builtin_type(std::size_t size)
|
|
||||||
{ return data_type_traits<std::string>::builtin_type(size); }
|
|
||||||
|
|
||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, job::job_state &value)
|
static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_state &value) {
|
||||||
{
|
|
||||||
std::string enum_string;
|
std::string enum_string;
|
||||||
reader.read_value(id, index, enum_string, 64);
|
reader.read_value(id, index, enum_string, 64);
|
||||||
if (const auto enum_opt = job_state_enum.to_enum(enum_string)) {
|
if (const auto enum_opt = job_state_enum.to_enum(enum_string)) {
|
||||||
|
|
@ -119,25 +121,16 @@ struct matador::sql::data_type_traits<job::job_state, void>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static any_type create_value(const job::job_state &value)
|
static void write_value(attribute_writer &binder, const size_t index, const job::job_state &value) {
|
||||||
{
|
binder.write_value(index, job_state_enum.to_string(value));
|
||||||
return job_state_enum.to_string(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bind_value(parameter_binder &binder, size_t index, job::job_state &value)
|
|
||||||
{
|
|
||||||
binder.bind(index, job_state_enum.to_string(value));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct matador::sql::data_type_traits<job::job_mode, void>
|
struct matador::utils::data_type_traits<job::job_mode, void> {
|
||||||
{
|
static basic_type type( const std::size_t size) { return data_type_traits<std::string>::type(size); }
|
||||||
inline static data_type_t builtin_type(std::size_t size)
|
|
||||||
{ return data_type_traits<std::string>::builtin_type(size); }
|
|
||||||
|
|
||||||
static void read_value(query_result_reader &reader, const char *id, size_t index, job::job_mode &value)
|
static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_mode &value) {
|
||||||
{
|
|
||||||
std::string enum_string;
|
std::string enum_string;
|
||||||
reader.read_value(id, index, enum_string, 64);
|
reader.read_value(id, index, enum_string, 64);
|
||||||
if (const auto enum_opt = job_mode_enum.to_enum(enum_string)) {
|
if (const auto enum_opt = job_mode_enum.to_enum(enum_string)) {
|
||||||
|
|
@ -145,14 +138,8 @@ struct matador::sql::data_type_traits<job::job_mode, void>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static any_type create_value(const job::job_mode &value)
|
static void bind_value(attribute_writer &binder, const size_t index, const job::job_mode &value) {
|
||||||
{
|
binder.write_value(index, job_mode_enum.to_string(value));
|
||||||
return job_mode_enum.to_string(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bind_value(parameter_binder &binder, size_t index, job::job_mode &value)
|
|
||||||
{
|
|
||||||
binder.bind(index, job_mode_enum.to_string(value));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -168,7 +155,7 @@ QUERY_HELPER( temporary_table, id );
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
using namespace matador;
|
using namespace matador::object;
|
||||||
|
|
||||||
const std::string env_var{"MATADOR_BACKENDS_PATH"};
|
const std::string env_var{"MATADOR_BACKENDS_PATH"};
|
||||||
|
|
||||||
|
|
@ -178,118 +165,118 @@ int main() {
|
||||||
s.attach<book>( "books" );
|
s.attach<book>( "books" );
|
||||||
|
|
||||||
connection c( dns );
|
connection c( dns );
|
||||||
c.open();
|
auto result = c.open();
|
||||||
s.create( c );
|
// s.create( c );
|
||||||
|
//
|
||||||
auto create_authors_sql = c.query( s )
|
// auto create_authors_sql = c.query( s )
|
||||||
.create()
|
// .create()
|
||||||
.table<author>( qh::authors )
|
// .table<author>( qh::authors )
|
||||||
.execute();
|
// .execute();
|
||||||
|
//
|
||||||
c.query( s )
|
// c.query( s )
|
||||||
.create()
|
// .create()
|
||||||
.table<book>( qh::books )
|
// .table<book>( qh::books )
|
||||||
.execute();
|
// .execute();
|
||||||
|
//
|
||||||
std::cout << "SQL: " << create_authors_sql << "\n";
|
// std::cout << "SQL: " << create_authors_sql << "\n";
|
||||||
|
//
|
||||||
author mc;
|
// author mc;
|
||||||
mc.id = 1;
|
// mc.id = 1;
|
||||||
mc.first_name = "Michael";
|
// mc.first_name = "Michael";
|
||||||
mc.last_name = "Crichton";
|
// mc.last_name = "Crichton";
|
||||||
mc.date_of_birth = "19.8.1954";
|
// mc.date_of_birth = "19.8.1954";
|
||||||
mc.year_of_birth = 1954;
|
// mc.year_of_birth = 1954;
|
||||||
mc.distinguished = true;
|
// mc.distinguished = true;
|
||||||
auto insert_authors_sql = c.query( s )
|
// auto insert_authors_sql = c.query( s )
|
||||||
.insert()
|
// .insert()
|
||||||
.into( qh::authors )
|
// .into( qh::authors )
|
||||||
.values( mc )
|
// .values( mc )
|
||||||
.execute();
|
// .execute();
|
||||||
|
//
|
||||||
std::cout << "SQL: " << insert_authors_sql << "\n";
|
// std::cout << "SQL: " << insert_authors_sql << "\n";
|
||||||
|
//
|
||||||
auto result = c.query( s )
|
// auto result = c.query( s )
|
||||||
.select( qh::authors.columns )
|
// .select( qh::authors.columns )
|
||||||
.from( qh::authors )
|
// .from( qh::authors )
|
||||||
.fetch_all();
|
// .fetch_all();
|
||||||
|
//
|
||||||
for (const auto& row: result) { std::cout << "Author " << row.at( qh::authors.first_name ) << "\n"; }
|
// for (const auto& row: result) { std::cout << "Author " << row.at( qh::authors.first_name ) << "\n"; }
|
||||||
|
//
|
||||||
auto update_authors_sql = c.query( s )
|
// auto update_authors_sql = c.query( s )
|
||||||
.update( qh::authors )
|
// .update( qh::authors )
|
||||||
.set( {{qh::authors.first_name, "Stephen"},
|
// .set( {{qh::authors.first_name, "Stephen"},
|
||||||
{qh::authors.last_name, "King"}} )
|
// {qh::authors.last_name, "King"}} )
|
||||||
.where( qh::authors.last_name == "Crichton" )
|
// .where( qh::authors.last_name == "Crichton" )
|
||||||
.execute();
|
// .execute();
|
||||||
|
//
|
||||||
std::cout << "SQL: " << update_authors_sql << "\n";
|
// std::cout << "SQL: " << update_authors_sql << "\n";
|
||||||
|
//
|
||||||
auto authors = c.query( s )
|
// auto authors = c.query( s )
|
||||||
.select( qh::authors.columns )
|
// .select( qh::authors.columns )
|
||||||
.from( qh::authors )
|
// .from( qh::authors )
|
||||||
.fetch_all<author>();
|
// .fetch_all<author>();
|
||||||
|
//
|
||||||
for (const auto& a: authors) { std::cout << "Author " << a.first_name << "\n"; }
|
// for (const auto& a: authors) { std::cout << "Author " << a.first_name << "\n"; }
|
||||||
|
//
|
||||||
c.query( s )
|
// c.query( s )
|
||||||
.insert()
|
// .insert()
|
||||||
.into( qh::books )
|
// .into( qh::books )
|
||||||
.values( {2, "It", mc.id, 1980} )
|
// .values( {2, "It", mc.id, 1980} )
|
||||||
.execute();
|
// .execute();
|
||||||
|
//
|
||||||
c.query( s )
|
// c.query( s )
|
||||||
.insert()
|
// .insert()
|
||||||
.into( qh::books )
|
// .into( qh::books )
|
||||||
.values( {3, "Misery", mc.id, 1984} )
|
// .values( {3, "Misery", mc.id, 1984} )
|
||||||
.execute();
|
// .execute();
|
||||||
|
//
|
||||||
auto select_books_sql = c.query( s )
|
// auto select_books_sql = c.query( s )
|
||||||
.select( qh::books.columns, {qh::authors.last_name} )
|
// .select( qh::books.columns, {qh::authors.last_name} )
|
||||||
.from( qh::books )
|
// .from( qh::books )
|
||||||
.join_left( qh::authors )
|
// .join_left( qh::authors )
|
||||||
.on( qh::books.author_id == qh::authors.id )
|
// .on( qh::books.author_id == qh::authors.id )
|
||||||
.where( qh::books.published_in < 2008 && qh::authors.last_name == "King" )
|
// .where( qh::books.published_in < 2008 && qh::authors.last_name == "King" )
|
||||||
.group_by( qh::books.published_in )
|
// .group_by( qh::books.published_in )
|
||||||
.order_by( qh::books.title ).asc()
|
// .order_by( qh::books.title ).asc()
|
||||||
.limit( 5 )
|
// .limit( 5 )
|
||||||
.offset( 2 )
|
// .offset( 2 )
|
||||||
.fetch_all();
|
// .fetch_all();
|
||||||
|
//
|
||||||
for (const auto& r: select_books_sql) { std::cout << "R: " << r.at( qh::books.title ) << ", " << r.at( qh::authors.last_name ) << "\n"; }
|
// for (const auto& r: select_books_sql) { std::cout << "R: " << r.at( qh::books.title ) << ", " << r.at( qh::authors.last_name ) << "\n"; }
|
||||||
// SELECT book.title, book.id, book.author_id, book.published_in, author.name
|
// // SELECT book.title, book.id, book.author_id, book.published_in, author.name
|
||||||
// FROM book
|
// // FROM book
|
||||||
// INNER JOIN author ON book.author_id = author.id
|
// // INNER JOIN author ON book.author_id = author.id
|
||||||
// WHERE book.published_in < 2008 AND author.name = "Michael Crichton"
|
// // WHERE book.published_in < 2008 AND author.name = "Michael Crichton"
|
||||||
// ORDER BY "book.title" ASC
|
// // ORDER BY "book.title" ASC
|
||||||
// OFFSET 2 LIMIT 5
|
// // OFFSET 2 LIMIT 5
|
||||||
|
//
|
||||||
c.query( s ).drop().table( qh::books ).execute();
|
// c.query( s ).drop().table( qh::books ).execute();
|
||||||
|
//
|
||||||
auto drop_authors_sql = c.query( s )
|
// auto drop_authors_sql = c.query( s )
|
||||||
.drop()
|
// .drop()
|
||||||
.table( qh::authors )
|
// .table( qh::authors )
|
||||||
.execute();
|
// .execute();
|
||||||
|
//
|
||||||
std::cout << "SQL: " << drop_authors_sql << "\n";
|
// std::cout << "SQL: " << drop_authors_sql << "\n";
|
||||||
|
//
|
||||||
auto res = c.query( s )
|
// auto res = c.query( s )
|
||||||
.select( {qh::payload.id} )
|
// .select( {qh::payload.id} )
|
||||||
.from( qh::payload )
|
// .from( qh::payload )
|
||||||
.join_left( qh::job )
|
// .join_left( qh::job )
|
||||||
.on( qh::job.payload == qh::payload.id )
|
// .on( qh::job.payload == qh::payload.id )
|
||||||
.where(
|
// .where(
|
||||||
in( qh::payload.id, c.query( s )
|
// in( qh::payload.id, c.query( s )
|
||||||
.select( {qh::job.state} )
|
// .select( {qh::job.state} )
|
||||||
.from( qh::job )
|
// .from( qh::job )
|
||||||
.where( qh::job.state == job::job_state::Running )
|
// .where( qh::job.state == job::job_state::Running )
|
||||||
) &&
|
// ) &&
|
||||||
in( qh::payload.id, c.query( s )
|
// in( qh::payload.id, c.query( s )
|
||||||
.select( {qh::temporary_table.id} )
|
// .select( {qh::temporary_table.id} )
|
||||||
.from( qh::temporary_table ) )
|
// .from( qh::temporary_table ) )
|
||||||
)
|
// )
|
||||||
.build();
|
// .build();
|
||||||
// .fetch_value<unsigned long>();
|
// // .fetch_value<unsigned long>();
|
||||||
std::cout << "SQL: " << res.sql << "\n";
|
// std::cout << "SQL: " << res.sql << "\n";
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef OBJECT_PTR_HPP
|
||||||
|
#define OBJECT_PTR_HPP
|
||||||
|
|
||||||
|
namespace matador::object {
|
||||||
|
template <typename Type>
|
||||||
|
class object_ptr {
|
||||||
|
public:
|
||||||
|
Type* operator->() { return ptr; };
|
||||||
|
Type& operator*() { return *ptr; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type* ptr{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //OBJECT_PTR_HPP
|
||||||
|
|
@ -18,7 +18,10 @@ class schema {
|
||||||
public:
|
public:
|
||||||
typedef const_schema_node_iterator const_iterator; /**< Shortcut for the list const iterator. */
|
typedef const_schema_node_iterator const_iterator; /**< Shortcut for the list const iterator. */
|
||||||
|
|
||||||
schema();
|
/**
|
||||||
|
* Creates an empty schema
|
||||||
|
*/
|
||||||
|
explicit schema( const std::string& name = "");
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
utils::result<void, utils::error> attach(const std::string name, const std::string &parent = "") {
|
utils::result<void, utils::error> attach(const std::string name, const std::string &parent = "") {
|
||||||
|
|
@ -36,6 +39,11 @@ public:
|
||||||
utils::result<void, utils::error> attach(const std::string name) {
|
utils::result<void, utils::error> attach(const std::string name) {
|
||||||
auto node = schema_node::make_node<Type>(*this, name);
|
auto node = schema_node::make_node<Type>(*this, name);
|
||||||
|
|
||||||
|
auto result = attach_node(node, std::type_index(typeid(ParentType)));
|
||||||
|
if (!result) {
|
||||||
|
return utils::failure(result.err());
|
||||||
|
}
|
||||||
|
|
||||||
return utils::ok<void>();
|
return utils::ok<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,26 +61,46 @@ public:
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] const_iterator end() const;
|
[[nodiscard]] const_iterator end() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the schema contains
|
||||||
|
* no schema nodes.
|
||||||
|
*
|
||||||
|
* @return True if schema is empty
|
||||||
|
*/
|
||||||
[[nodiscard]] bool empty() const;
|
[[nodiscard]] bool empty() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current number of schema node.
|
||||||
|
*
|
||||||
|
* @return Number of schema nodes
|
||||||
|
*/
|
||||||
[[nodiscard]] size_t size() const;
|
[[nodiscard]] size_t size() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the schema.
|
||||||
|
*
|
||||||
|
* @return The name of the schema
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::string name() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using t_node_map = std::unordered_map<std::string, std::shared_ptr<schema_node>>;
|
|
||||||
// type_index -> [name -> prototype]
|
|
||||||
using t_type_index_node_map = std::unordered_map<std::type_index, t_node_map>;
|
|
||||||
using node_ptr = std::shared_ptr<schema_node>;
|
using node_ptr = std::shared_ptr<schema_node>;
|
||||||
|
using t_node_map = std::unordered_map<std::string, node_ptr>;
|
||||||
|
using t_type_index_node_map = std::unordered_map<std::type_index, node_ptr>;
|
||||||
|
|
||||||
utils::result<std::shared_ptr<schema_node>, utils::error> attach_node(const std::shared_ptr<schema_node> &node,
|
[[nodiscard]] utils::result<std::shared_ptr<schema_node>, utils::error> attach_node(const std::shared_ptr<schema_node> &node,
|
||||||
const std::string &parent);
|
const std::string &parent);
|
||||||
utils::result<std::shared_ptr<schema_node>, utils::error> find_parent(const std::string &name) const;
|
[[nodiscard]] utils::result<std::shared_ptr<schema_node>, utils::error> attach_node(const std::shared_ptr<schema_node> &node,
|
||||||
utils::result<std::shared_ptr<schema_node>, utils::error> find_node(const std::string &name) const;
|
const std::type_index &type_index);
|
||||||
|
[[nodiscard]] utils::result<std::shared_ptr<schema_node>, utils::error> find_node(const std::string &name) const;
|
||||||
|
[[nodiscard]] utils::result<std::shared_ptr<schema_node>, utils::error> find_node(const std::type_index &type_index) const;
|
||||||
|
|
||||||
void push_back_child(const node_ptr &parent, const node_ptr &child);
|
[[nodiscard]] bool has_node(const std::type_index& index, const std::string &name) const;
|
||||||
|
|
||||||
bool has_node(const std::type_index& index, const std::string &name) const;
|
static void push_back_child(const node_ptr &parent, const node_ptr &child);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string name_;
|
||||||
std::shared_ptr<schema_node> root_;
|
std::shared_ptr<schema_node> root_;
|
||||||
|
|
||||||
t_node_map node_map_;
|
t_node_map node_map_;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ class schema;
|
||||||
|
|
||||||
class schema_node final {
|
class schema_node final {
|
||||||
public:
|
public:
|
||||||
|
using node_ptr = std::shared_ptr<schema_node>;
|
||||||
|
|
||||||
template < typename Type >
|
template < typename Type >
|
||||||
static std::shared_ptr<schema_node> make_node(schema& tree, const std::string& name) {
|
static std::shared_ptr<schema_node> make_node(schema& tree, const std::string& name) {
|
||||||
return std::shared_ptr<schema_node>(new schema_node(tree, name, static_cast<Type*>(nullptr)));
|
return std::shared_ptr<schema_node>(new schema_node(tree, name, static_cast<Type*>(nullptr)));
|
||||||
|
|
@ -41,6 +43,9 @@ public:
|
||||||
*/
|
*/
|
||||||
void insert(const std::shared_ptr<schema_node> &child);
|
void insert(const std::shared_ptr<schema_node> &child);
|
||||||
|
|
||||||
|
[[nodiscard]] node_ptr next() const;
|
||||||
|
[[nodiscard]] node_ptr prev() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit schema_node(schema& tree);
|
explicit schema_node(schema& tree);
|
||||||
template < typename Type >
|
template < typename Type >
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ public:
|
||||||
*
|
*
|
||||||
* @return Returns iterator before incrementing.
|
* @return Returns iterator before incrementing.
|
||||||
*/
|
*/
|
||||||
const_schema_node_iterator operator++(int);
|
const_schema_node_iterator operator++( int );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre increments the iterator
|
* Pre increments the iterator
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
class schema;
|
|
||||||
class connection_impl;
|
class connection_impl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef QUERY_QUERY_HELPER_HPP
|
||||||
|
#define QUERY_QUERY_HELPER_HPP
|
||||||
|
|
||||||
|
#include "matador/utils/macro_map.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/table.hpp"
|
||||||
|
#include "matador/sql/column.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#define FIELD(x) const sql::column x{*this, #x, ""};
|
||||||
|
|
||||||
|
#define QUERY_HELPER(C, ...) \
|
||||||
|
namespace matador::qh { \
|
||||||
|
namespace internal { \
|
||||||
|
struct C##_query : sql::table { \
|
||||||
|
C##_query() : table(#C) {} \
|
||||||
|
MAP(FIELD, __VA_ARGS__) \
|
||||||
|
}; } \
|
||||||
|
static const internal:: C##_query C; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //QUERY_QUERY_HELPER_HPP
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef QUERY_MACRO_MAP_HPP
|
||||||
|
#define QUERY_MACRO_MAP_HPP
|
||||||
|
|
||||||
|
#define EVAL0(...) __VA_ARGS__
|
||||||
|
#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
|
||||||
|
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
|
||||||
|
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
|
||||||
|
#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
|
||||||
|
#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
|
||||||
|
|
||||||
|
#define MAP_END(...)
|
||||||
|
#define MAP_OUT
|
||||||
|
#define MAP_COMMA ,
|
||||||
|
|
||||||
|
#define MAP_GET_END2() 0, MAP_END
|
||||||
|
#define MAP_GET_END1(...) MAP_GET_END2
|
||||||
|
#define MAP_GET_END(...) MAP_GET_END1
|
||||||
|
#define MAP_NEXT0(test, next, ...) next MAP_OUT
|
||||||
|
#define MAP_NEXT1(test, next) MAP_NEXT0(test, next, 0)
|
||||||
|
#define MAP_NEXT(test, next) MAP_NEXT1(MAP_GET_END test, next)
|
||||||
|
|
||||||
|
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP1)(f, peek, __VA_ARGS__)
|
||||||
|
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP0)(f, peek, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MAP_LIST_NEXT1(test, next) MAP_NEXT0(test, MAP_COMMA next, 0)
|
||||||
|
#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next)
|
||||||
|
|
||||||
|
#define MAP_LIST0(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST1)(f, peek, __VA_ARGS__)
|
||||||
|
#define MAP_LIST1(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST0)(f, peek, __VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the function macro `f` to each of the remaining parameters.
|
||||||
|
*/
|
||||||
|
#define MAP(f, ...) EVAL(MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the function macro `f` to each of the remaining parameters and
|
||||||
|
* inserts commas between the results.
|
||||||
|
*/
|
||||||
|
#define MAP_LIST(f, ...) EVAL(MAP_LIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
|
||||||
|
|
||||||
|
#endif //QUERY_MACRO_MAP_HPP
|
||||||
|
|
@ -20,6 +20,7 @@ add_library(matador-core STATIC
|
||||||
../../include/matador/utils/foreign_attributes.hpp
|
../../include/matador/utils/foreign_attributes.hpp
|
||||||
../../include/matador/utils/identifier.hpp
|
../../include/matador/utils/identifier.hpp
|
||||||
../../include/matador/utils/library.hpp
|
../../include/matador/utils/library.hpp
|
||||||
|
../../include/matador/utils/macro_map.hpp
|
||||||
../../include/matador/utils/os.hpp
|
../../include/matador/utils/os.hpp
|
||||||
../../include/matador/utils/placeholder.hpp
|
../../include/matador/utils/placeholder.hpp
|
||||||
../../include/matador/utils/result.hpp
|
../../include/matador/utils/result.hpp
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,9 @@ utils::error make_error(const error_code ec, const std::string& msg) {
|
||||||
return utils::error(ec, msg);
|
return utils::error(ec, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
schema::schema()
|
schema::schema( const std::string& name)
|
||||||
: root_(std::shared_ptr<schema_node>(new schema_node(*this))) {
|
: name_(name)
|
||||||
|
, root_(std::shared_ptr<schema_node>(new schema_node(*this))) {
|
||||||
root_->first_child_ = std::shared_ptr<schema_node>(new schema_node(*this));
|
root_->first_child_ = std::shared_ptr<schema_node>(new schema_node(*this));
|
||||||
root_->last_child_ = std::shared_ptr<schema_node>(new schema_node(*this));
|
root_->last_child_ = std::shared_ptr<schema_node>(new schema_node(*this));
|
||||||
root_->first_child_->next_sibling_ = root_->last_child_;
|
root_->first_child_->next_sibling_ = root_->last_child_;
|
||||||
|
|
@ -30,64 +31,67 @@ size_t schema::size() const {
|
||||||
return static_cast<size_t>(std::distance(begin(), end()));
|
return static_cast<size_t>(std::distance(begin(), end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string schema::name() const {
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
utils::result<std::shared_ptr<schema_node>, utils::error> schema::attach_node(const std::shared_ptr<schema_node> &node,
|
utils::result<std::shared_ptr<schema_node>, utils::error> schema::attach_node(const std::shared_ptr<schema_node> &node,
|
||||||
const std::string &parent) {
|
const std::string &parent) {
|
||||||
if (!has_node(node->type_index(), node->name())) {
|
if (has_node(node->type_index(), node->name())) {
|
||||||
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists."));
|
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set node to root node
|
// set node to root node
|
||||||
auto parent_node = root_;
|
auto parent_node = root_;
|
||||||
auto result = find_parent(parent);
|
if (!parent.empty()) {
|
||||||
|
auto result = find_node(parent);
|
||||||
|
if (!result.is_ok() && result.err().ec() != error_code::NodeNotFound) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
parent_node = *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
push_back_child(parent_node, node);
|
||||||
|
|
||||||
|
// Todo: check return value
|
||||||
|
node_map_.insert({node->name(), node})/*.first*/;
|
||||||
|
type_index_node_map_.insert({node->type_index(), node});
|
||||||
|
|
||||||
|
return utils::ok(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::result<std::shared_ptr<schema_node>, utils::error> schema::attach_node( const std::shared_ptr<schema_node>& node,
|
||||||
|
const std::type_index& type_index ) {
|
||||||
|
if (has_node(node->type_index(), node->name())) {
|
||||||
|
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists."));
|
||||||
|
}
|
||||||
|
auto result = find_node(type_index);
|
||||||
if (!result.is_ok() && result.err().ec() != error_code::NodeNotFound) {
|
if (!result.is_ok() && result.err().ec() != error_code::NodeNotFound) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
parent_node = *result;
|
|
||||||
|
|
||||||
push_back_child(root_, node);
|
push_back_child(*result, node);
|
||||||
|
|
||||||
// if (!pk.is_null()) {
|
|
||||||
// node->primary_key_ = pk;
|
|
||||||
// }
|
|
||||||
// store prototype in map
|
|
||||||
// Todo: check return value
|
// Todo: check return value
|
||||||
node_map_.insert(std::make_pair(node->name(), node))/*.first*/;
|
node_map_.insert({node->name(), node})/*.first*/;
|
||||||
type_index_node_map_[node->type_index()].insert(std::make_pair(node->name(), node));
|
type_index_node_map_.insert({node->type_index(), node});
|
||||||
|
|
||||||
// return nptr.release();
|
return utils::ok(node);
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::result<std::shared_ptr<schema_node>, utils::error> schema::find_parent(const std::string &name) const {
|
|
||||||
if (name.empty()) {
|
|
||||||
return utils::failure(make_error(error_code::Failure, "Name of parent cannot be empty"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return find_node(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::result<std::shared_ptr<schema_node>, utils::error> schema::find_node(const std::string &name) const {
|
utils::result<std::shared_ptr<schema_node>, utils::error> schema::find_node(const std::string &name) const {
|
||||||
// first search in the prototype map
|
// first search in the prototype map
|
||||||
const auto i = node_map_.find(name);
|
const auto i = node_map_.find(name);
|
||||||
if (i == node_map_.end()) {
|
if (i == node_map_.end()) {
|
||||||
// if not found search in the typeid to prototype map
|
return utils::failure(make_error(error_code::NodeNotFound, "Couldn't find node by name '" + name + "'"));
|
||||||
// const auto j = type_index_node_map_.find(name);
|
}
|
||||||
// if (j == type_index_node_map_.end()) {
|
return utils::ok(i->second);
|
||||||
// return utils::failure(
|
}
|
||||||
// make_error(error_code::NodeNotFound, std::string("Could not find node with name '") + name + "'"));
|
|
||||||
// }
|
utils::result<std::shared_ptr<schema_node>, utils::error> schema::find_node( const std::type_index& type_index ) const {
|
||||||
// const t_node_map &val = j->second;
|
const auto i = type_index_node_map_.find(type_index);
|
||||||
/*
|
if (i == type_index_node_map_.end()) {
|
||||||
* if size is greater one (1) the name
|
return utils::failure(make_error(error_code::NodeNotFound, "Couldn't find node by type '" + std::string(type_index.name()) + "'"));
|
||||||
* is a typeid and has more than one prototype
|
|
||||||
* node and therefor it is not unique and an
|
|
||||||
* exception is thrown
|
|
||||||
*/
|
|
||||||
// if (val.size() > 1) {
|
|
||||||
// return utils::failure(make_error(error_code::NodeNotFound, std::string("Type id '") + name + "' is not unique"));
|
|
||||||
// }
|
|
||||||
// // return the only prototype
|
|
||||||
// return utils::ok(val.begin()->second);
|
|
||||||
}
|
}
|
||||||
return utils::ok(i->second);
|
return utils::ok(i->second);
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +100,12 @@ void schema::push_back_child(const node_ptr &parent, const node_ptr &child) {
|
||||||
child->parent_ = parent;
|
child->parent_ = parent;
|
||||||
child->previous_sibling_ = parent->last_child_->previous_sibling_;
|
child->previous_sibling_ = parent->last_child_->previous_sibling_;
|
||||||
child->next_sibling_ = parent->last_child_;
|
child->next_sibling_ = parent->last_child_;
|
||||||
|
/*
|
||||||
|
* +-----------------------------<- (first) parent (last) -> ----------------------------+
|
||||||
|
* | |
|
||||||
|
* first (next) -> <- (prev) child_1 (next) -> <- (prev) new_child (next) -> <- (prev) last
|
||||||
|
* ^^^^^^^ inserted ^^^^^^
|
||||||
|
*/
|
||||||
parent->last_child_->previous_sibling_->next_sibling_ = child;
|
parent->last_child_->previous_sibling_->next_sibling_ = child;
|
||||||
parent->last_child_->previous_sibling_ = child;
|
parent->last_child_->previous_sibling_ = child;
|
||||||
// set depth
|
// set depth
|
||||||
|
|
|
||||||
|
|
@ -57,4 +57,38 @@ void schema_node::insert(const std::shared_ptr<schema_node> &child) {
|
||||||
// // 3. last
|
// // 3. last
|
||||||
// child->op_last = op_last;
|
// child->op_last = op_last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
schema_node::node_ptr schema_node::next() const {
|
||||||
|
// if we have a child, child is the next iterator to return
|
||||||
|
// (if we don't do iterate over the siblings)
|
||||||
|
if (first_child_ && first_child_->next_sibling_ != last_child_) {
|
||||||
|
return first_child_->next_sibling_;
|
||||||
|
}
|
||||||
|
// if there is no child, we check for sibling
|
||||||
|
// if there is a sibling, this is our next iterator to return
|
||||||
|
// if not, we go back to the parent
|
||||||
|
auto *node = this;
|
||||||
|
while (node->parent_ && node->next_sibling_ == node->parent_->last_child_) {
|
||||||
|
node = node->parent_.get();
|
||||||
|
}
|
||||||
|
return node->parent_ ? node->next_sibling_ : node->last_child_;
|
||||||
|
}
|
||||||
|
|
||||||
|
schema_node::node_ptr schema_node::prev() const {
|
||||||
|
// if node has a previous sibling, we set it
|
||||||
|
// as our next iterator. then we check if there
|
||||||
|
// are last children. if so, we set the last-last
|
||||||
|
// child as our iterator
|
||||||
|
if (previous_sibling_ && previous_sibling_->previous_sibling_) {
|
||||||
|
auto node = previous_sibling_;
|
||||||
|
while (node->last_child_ && node->first_child_->next_sibling_ != node->last_child_) {
|
||||||
|
node = node->last_child_->previous_sibling_;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
// if there is no previous sibling, our next iterator
|
||||||
|
// is the parent of the node
|
||||||
|
return parent_->parent_ ? parent_ : parent_->first_child_->next_sibling_;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,7 @@ const_schema_node_iterator& const_schema_node_iterator::operator++()
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const_schema_node_iterator const_schema_node_iterator::operator++(int)
|
const_schema_node_iterator const_schema_node_iterator::operator++( int ) {
|
||||||
{
|
|
||||||
const std::shared_ptr<value_type> tmp = node_;
|
const std::shared_ptr<value_type> tmp = node_;
|
||||||
increment();
|
increment();
|
||||||
return const_schema_node_iterator(tmp);
|
return const_schema_node_iterator(tmp);
|
||||||
|
|
@ -65,42 +64,15 @@ void const_schema_node_iterator::increment()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have a child, child is the next iterator to return
|
node_ = node_->next();
|
||||||
// (if we don't do iterate over the siblings)
|
|
||||||
if (node_->first_child_ && node_->first_child_->next_sibling_ != node_->last_child_) {
|
|
||||||
node_ = node_->first_child_->next_sibling_;
|
|
||||||
} else {
|
|
||||||
// if there is no child, we check for sibling
|
|
||||||
// if there is a sibling, this is our next iterator to return
|
|
||||||
// if not, we go back to the parent
|
|
||||||
std::shared_ptr<value_type> node = node_;
|
|
||||||
while (node_->parent_ && node_->next_sibling_ == node_->parent_->last_child_) {
|
|
||||||
node = node->parent_;
|
|
||||||
}
|
|
||||||
node_ = node_->next_sibling_;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
void const_schema_node_iterator::decrement()
|
void const_schema_node_iterator::decrement()
|
||||||
{
|
{
|
||||||
if (!node_) {
|
if (!node_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if node has a previous sibling, we set it
|
|
||||||
// as our next iterator. then we check if there
|
node_ = node_->prev();
|
||||||
// are last children. if so, we set the last-last
|
|
||||||
// child as our iterator
|
|
||||||
if (node_->previous_sibling_ && node_->previous_sibling_->previous_sibling_) {
|
|
||||||
std::shared_ptr<value_type> node = node_->previous_sibling_;
|
|
||||||
while (node_->last_child_ && node_->first_child_->next_sibling_ != node_->last_child_) {
|
|
||||||
node = node->last_child_->previous_sibling_;
|
|
||||||
}
|
|
||||||
node_ = node;
|
|
||||||
// if there is no previous sibling, our next iterator
|
|
||||||
// is the parent of the node
|
|
||||||
} else {
|
|
||||||
node_ = node_->parent_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +59,7 @@ add_library(matador-orm STATIC
|
||||||
../../include/matador/sql/internal/object_result_binder.hpp
|
../../include/matador/sql/internal/object_result_binder.hpp
|
||||||
../../include/matador/sql/internal/query_result_impl.hpp
|
../../include/matador/sql/internal/query_result_impl.hpp
|
||||||
../../include/matador/sql/query_context.hpp
|
../../include/matador/sql/query_context.hpp
|
||||||
|
../../include/matador/sql/query_macro.hpp
|
||||||
../../include/matador/sql/query_result.hpp
|
../../include/matador/sql/query_result.hpp
|
||||||
../../include/matador/sql/record.hpp
|
../../include/matador/sql/record.hpp
|
||||||
../../include/matador/sql/statement.hpp
|
../../include/matador/sql/statement.hpp
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ add_executable(CoreTests
|
||||||
utils/FieldAttributeTest.cpp
|
utils/FieldAttributeTest.cpp
|
||||||
utils/VersionTest.cpp
|
utils/VersionTest.cpp
|
||||||
utils/StringTest.cpp
|
utils/StringTest.cpp
|
||||||
object/PrototypeTreeTest.cpp
|
object/SchemaTest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(CoreTests matador-core Catch2::Catch2WithMain)
|
target_link_libraries(CoreTests matador-core Catch2::Catch2WithMain)
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,52 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "matador/object/schema.hpp"
|
#include "matador/object/schema.hpp"
|
||||||
|
|
||||||
struct node {};
|
struct node {};
|
||||||
|
|
||||||
using namespace matador;
|
using namespace matador;
|
||||||
|
|
||||||
struct person {
|
struct person {
|
||||||
virtual ~person() = default;
|
virtual ~person() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct student final : person {};
|
struct student final : person {};
|
||||||
struct teacher final : person {};
|
struct teacher final : person {};
|
||||||
|
|
||||||
TEST_CASE("Test empty prototype tree", "[prototype_tree][empty]") {
|
TEST_CASE("Test empty prototype tree", "[schema_node][empty]") {
|
||||||
const object::schema tree;
|
const object::schema tree;
|
||||||
|
|
||||||
REQUIRE( tree.empty() );
|
REQUIRE( tree.empty() );
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test add type to prototype tree", "[prototype_tree][add]") {
|
TEST_CASE("Test add type to prototype tree", "[schema_node][add]") {
|
||||||
object::schema tree;
|
object::schema tree;
|
||||||
|
|
||||||
REQUIRE( tree.empty() );
|
REQUIRE( tree.empty() );
|
||||||
|
|
||||||
auto res = tree.attach<person>("person");
|
auto res = tree.attach<person>("person");
|
||||||
REQUIRE( res.is_ok() );
|
REQUIRE( res.is_ok() );
|
||||||
res = tree.attach<student, person>("student");
|
res = tree.attach<student, person>("student");
|
||||||
REQUIRE( res.is_ok() );
|
REQUIRE( res.is_ok() );
|
||||||
res = tree.attach<teacher, person>("teacher");
|
res = tree.attach<teacher, person>("teacher");
|
||||||
REQUIRE( res.is_ok() );
|
REQUIRE( res.is_ok() );
|
||||||
|
|
||||||
REQUIRE( tree.size() == 3 );
|
REQUIRE( !tree.empty() );
|
||||||
}
|
REQUIRE( tree.size() == 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test next and previous of schema node", "[schema_node][next][previous]") {
|
||||||
|
object::schema tree;
|
||||||
|
|
||||||
|
REQUIRE( tree.empty() );
|
||||||
|
|
||||||
|
auto res = tree.attach<person>("person");
|
||||||
|
REQUIRE( res.is_ok() );
|
||||||
|
|
||||||
|
REQUIRE( tree.size() == 1 );
|
||||||
|
|
||||||
|
auto it = tree.begin();
|
||||||
|
REQUIRE( it->name() == "person" );
|
||||||
|
REQUIRE( (--it)->name() == "person" );
|
||||||
|
REQUIRE( ++it == tree.end() );
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue