Skip to content

Commit

Permalink
Implement parameter traits for arrays of pair/tuple
Browse files Browse the repository at this point in the history
  • Loading branch information
d-frey committed Dec 2, 2024
1 parent 5519814 commit e8e1ca7
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 13 deletions.
2 changes: 1 addition & 1 deletion include/tao/pq/parameter_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ namespace tao::pq
{ t.template value< 0 >() } -> std::same_as< const char* >;
{ t.template length< 0 >() } -> std::same_as< int >;
{ t.template format< 0 >() } -> std::same_as< int >;
// TODO: { t.template element< 0 >( s ) } -> std::same_as< void >;
{ t.template element< 0 >( s ) } -> std::same_as< void >;
{ t.template copy_to< 0 >( s ) } -> std::same_as< void >;
};

Expand Down
26 changes: 24 additions & 2 deletions include/tao/pq/parameter_traits_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,17 @@ namespace tao::pq

namespace internal
{
template< typename T >
void to_array( std::string& data, const T& v );

template< typename T, std::size_t... Is >
void to_array_indexed( std::string& data, const T& v, std::index_sequence< Is... > /*unused*/ )
{
data += '{';
( ( v.template element< Is >( data ), data += ',' ), ... );
*data.rbegin() = '}';
}

template< typename T >
void to_array( std::string& data, const T& v )
{
Expand All @@ -66,8 +77,13 @@ namespace tao::pq
}
else {
const auto t = parameter_traits< T >( v );
static_assert( t.columns == 1 );
t.template element< 0 >( data );
if constexpr( t.columns == 1 ) {
t.template element< 0 >( data );
}
else {
static_assert( t.columns > 1 );
internal::to_array_indexed( data, t, std::make_index_sequence< t.columns >() );
}
}
}

Expand Down Expand Up @@ -113,6 +129,12 @@ namespace tao::pq
return 0;
}

template< std::size_t I >
void element( std::string& data ) const
{
internal::array_append( data, m_data );
}

template< std::size_t I >
void copy_to( std::string& data ) const
{
Expand Down
6 changes: 6 additions & 0 deletions include/tao/pq/parameter_traits_pair.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ struct tao::pq::parameter_traits< std::pair< T, U > >
return std::get< gen::template outer< I > >( m_pair ).template format< gen::template inner< I > >();
}

template< std::size_t I >
void element( std::string& data ) const
{
std::get< gen::template outer< I > >( m_pair ).template element< gen::template inner< I > >( data );
}

template< std::size_t I >
void copy_to( std::string& data ) const
{
Expand Down
7 changes: 7 additions & 0 deletions include/tao/pq/parameter_traits_tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <tao/pq/parameter_traits.hpp>

template< typename... Ts >
requires( sizeof...( Ts ) != 0 )
struct tao::pq::parameter_traits< std::tuple< Ts... > >
{
private:
Expand Down Expand Up @@ -60,6 +61,12 @@ struct tao::pq::parameter_traits< std::tuple< Ts... > >
return std::get< gen::template outer< I > >( m_tuple ).template format< gen::template inner< I > >();
}

template< std::size_t I >
void element( std::string& data ) const
{
std::get< gen::template outer< I > >( m_tuple ).template element< gen::template inner< I > >( data );
}

template< std::size_t I >
void copy_to( std::string& data ) const
{
Expand Down
1 change: 1 addition & 0 deletions include/tao/pq/result_traits_tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct tao::pq::result_traits< std::tuple< T > >
};

template< typename... Ts >
requires( sizeof...( Ts ) != 0 )
struct tao::pq::result_traits< std::tuple< Ts... > >
{
static_assert( sizeof...( Ts ) != 0, "conversion to empty std::tuple<> not support" );
Expand Down
62 changes: 52 additions & 10 deletions src/test/pq/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ namespace
connection->execute( "DROP TABLE IF EXISTS tao_array_test" );
connection->execute( "CREATE TABLE tao_array_test ( a TEXT[] )" );

const std::vector< std::optional< std::string > > v = { "FOO", "", "{BAR\\BAZ\"B,L;A}", "NULL", std::nullopt };
using type = std::vector< std::optional< std::string > >;
const type v = { "FOO", "", "{BAR\\BAZ\"B,L;A}", "NULL", std::nullopt };
connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v );

const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< std::optional< std::string > > >();
const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< type >();
TEST_ASSERT( r.size() == 5 );
TEST_ASSERT( r[ 0 ] == "FOO" );
TEST_ASSERT( r[ 1 ]->empty() ); // NOLINT(bugprone-unchecked-optional-access)
Expand All @@ -68,27 +69,68 @@ namespace
connection->execute( "DROP TABLE IF EXISTS tao_array_test" );
connection->execute( "CREATE TABLE tao_array_test ( a TEXT[][] NOT NULL )" );

const std::vector< std::vector< std::string > > v = { { "1", "F\"O\\O", "NULL" }, { "4", " XYZ ", "6" } };
using type = std::vector< std::vector< std::string > >;
const type v = { { "1", "F\"O\\O", "NULL" }, { "4", " XYZ ", "6" } };
connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v );

const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< std::vector< std::string > > >();
const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< type >();
TEST_ASSERT( r == v );
}

{
connection->execute( "DROP TABLE IF EXISTS tao_array_test" );
connection->execute( "CREATE TABLE tao_array_test ( a BYTEA[][] NOT NULL )" );
connection->execute( "CREATE TABLE tao_array_test ( a TEXT[][] NOT NULL )" );

using type = std::vector< std::pair< std::string, std::string > >;
const type v = { { "1", "F\"O\\O" }, { "4", " XYZ " } };
connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v );

// TODO: Add result_traits...
// const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< type >();
// TEST_ASSERT( r == v );
}

const std::vector< tao::pq::binary > v = { tao::pq::to_binary( "1" ),
tao::pq::binary(),
tao::pq::to_binary( "F\"O\\O" ),
tao::pq::to_binary( "NU\0LL" ) };
{
connection->execute( "DROP TABLE IF EXISTS tao_array_test" );
connection->execute( "CREATE TABLE tao_array_test ( a TEXT[][] NOT NULL )" );

using type = std::vector< std::tuple< int, std::string, std::optional< std::string > > >;
const type v = { { 1, "F\"O\\O", std::nullopt }, { 4, " XYZ ", "BAR" } };
connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v );

const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< std::vector< tao::pq::binary > >();
// TODO: Add result_traits...
// const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< type >();
// TEST_ASSERT( r == v );
}

{
connection->execute( "DROP TABLE IF EXISTS tao_array_test" );
connection->execute( "CREATE TABLE tao_array_test ( a TEXT[] NOT NULL )" );

// note: a tuple with only one element is *not* treated as an array
using type = std::vector< std::tuple< std::string > >;
const type v = { { "F\"O\\O" }, { " XYZ " } };
connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v );

const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< type >();
TEST_ASSERT( r == v );
}

{
connection->execute( "DROP TABLE IF EXISTS tao_array_test" );
connection->execute( "CREATE TABLE tao_array_test ( a BYTEA[][] NOT NULL )" );

using type = std::vector< tao::pq::binary >;
const type v = { tao::pq::to_binary( "1" ),
tao::pq::binary(),
tao::pq::to_binary( "F\"O\\O" ),
tao::pq::to_binary( "NU\0LL" ) };
connection->execute( "INSERT INTO tao_array_test VALUES ( $1 )", v );

const auto r = connection->execute( "SELECT * FROM tao_array_test" ).as< type >();
TEST_ASSERT( r == v );
}

TEST_THROWS( connection->execute( "SELECT $1", "" ).as< std::vector< std::string > >() );
TEST_THROWS( connection->execute( "SELECT $1", "{" ).as< std::vector< std::string > >() );
TEST_THROWS( connection->execute( "SELECT $1", "{FOO" ).as< std::vector< std::string > >() );
Expand Down

0 comments on commit e8e1ca7

Please sign in to comment.