Skip to content

Commit

Permalink
Factory for stream_from with from_query.
Browse files Browse the repository at this point in the history
This is my way out of the quagmire of constructor overloads.  Instead of
constructing a `stream_from` and adding a `from_query` argument just to
disambiguate the call, you can now call `stream_from::query()`.

Obviously I will also want to do this for the `from_table` case.  But
I'd like to get those overloads right from the start, and that means
Concepts, which means C++20: `span`, `range`, and being able to treat
all iterator types differently from all string types in overloading
resolution.  Or perhaps for starters I'll find a nice way to tell the
overload for "one column, as a string" apart from the overload for
"run-time number of columns, as a container."  Or similar for "two
columns, as strings" versus "run-time number of columns, as a pair of
iterators."
  • Loading branch information
jtv committed Jan 3, 2021
1 parent 9e9d625 commit c0c25ed
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 25 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Error messages more often report query description, if given.
- Suppress spurious deprecation messages on Visual Studio. (#402)
- Correct error when prepared/param statement clashes with tx focus. (#401)
- `from_stream` with `from_query` now has a convenient factory function.
7.3.0
- `stream_to` now quotes and escapes its table name.
- Removed `transaction_base::classname()`. Did anyone ever use it?
Expand Down
5 changes: 2 additions & 3 deletions include/pqxx/doc/streams.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ And, you can start processing before you've received all the data.
Every row is converted to a tuple type of your choice as you read it. You
stream into the tuple:

pqxx::stream_from stream{
tx, pqxx::from_query,
"SELECT name, points FROM score"};
auto stream pqxx::stream_from::query(
tx, "SELECT name, points FROM score");
std::tuple<std::string, int> row;
while (stream >> row)
process(row);
Expand Down
2 changes: 1 addition & 1 deletion include/pqxx/internal/ignore-deprecated-post.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@

#endif // __GNUC__
#ifdef _MSC_VER
#pragma warning(pop)
# pragma warning(pop)
#endif
4 changes: 2 additions & 2 deletions include/pqxx/internal/ignore-deprecated-pre.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@

#endif // __GNUC__
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4996)
# pragma warning(push)
# pragma warning(disable : 4996)
#endif
46 changes: 34 additions & 12 deletions include/pqxx/stream_from.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,12 @@ public:
using raw_line =
std::pair<std::unique_ptr<char, std::function<void(char *)>>, std::size_t>;

// TODO: Change to "named constructor" style.
/// Execute query, and stream over the results.
/** The query can be a SELECT query or a VALUES query; or it can be an
/**
* @name Streaming queries
*
* You can use @c stream_from to execute a query, and stream its results.
*
* The query can be a SELECT query or a VALUES query; or it can be an
* UPDATE, INSERT, or DELETE with a RETURNING clause.
*
* The query is executed as part of a COPY statement, so there are additional
Expand All @@ -81,27 +84,44 @@ public:
*
* https://www.postgresql.org/docs/current/sql-copy.html
*/
//@{
/// Factory: Execute query, and stream the results.
static stream_from query(transaction_base &tx, std::string_view q)
{
return stream_from{tx, from_query, q};
}

/// Execute query, and stream over the results.
/** This is the awkward way to construct a @c stream_from. It uses a marker
* argument type to disambiguate overloads.
*
* Where possible, use factory function @c query() instead.
*/
stream_from(transaction_base &, from_query_t, std::string_view query);
//@}

/// Stream all rows in table, all columns.
/** The table name cannot include a schema name. If you need to specify a
* schema name, stream from a query rather than from a table.
/**
* @name Streaming tables
*
* You can use @c stream_from to read a table's contents.
*
* Streaming does not work from a view, and the table name cannot include a
* schema name, and there are no guarantees about ordering. If you need any
* of those things, consider streaming from a query instead.
*/
//@{
// TODO: Replace constructors with factories. Use Concepts.

/// Stream all rows in table, all columns.
stream_from(transaction_base &, from_table_t, std::string_view table);

/// Stream given columns from all rows in table.
/** The table name cannot include a schema name. If you need to specify a
* schema name, stream from a query rather than from a table.
*/
template<typename Iter>
stream_from(
transaction_base &, from_table_t, std::string_view table,
Iter columns_begin, Iter columns_end);

/// Stream given columns from all rows in table.
/** The table name cannot include a schema name. If you need to specify a
* schema name, stream from a query rather than from a table.
*/
template<typename Columns>
stream_from(
transaction_base &tx, from_table_t, std::string_view table,
Expand All @@ -125,6 +145,7 @@ public:
[[deprecated("Use the from_table_t overload instead.")]] stream_from(
transaction_base &, std::string_view table, Iter columns_begin,
Iter columns_end);
//@}

~stream_from() noexcept;

Expand Down Expand Up @@ -156,6 +177,7 @@ public:
template<typename... Vs>
stream_from &operator>>(std::variant<Vs...> &) = delete;

// TODO: Hide this from the public.
/// Iterate over this stream. Supports range-based "for" loops.
/** Produces an input iterator over the stream.
*
Expand Down
10 changes: 5 additions & 5 deletions test/unit/test_stream_from.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ namespace
void test_nonoptionals(pqxx::connection &connection)
{
pqxx::work tx{connection};
pqxx::stream_from extractor{
tx, pqxx::from_query, "SELECT * FROM stream_from_test ORDER BY number0"};
auto extractor{pqxx::stream_from::query(
tx, "SELECT * FROM stream_from_test ORDER BY number0")};
PQXX_CHECK(extractor, "stream_from failed to initialize.");

std::tuple<int, std::string, int, ipv4, std::string, bytea> got_tuple;
Expand Down Expand Up @@ -80,7 +80,7 @@ void test_nonoptionals(pqxx::connection &connection)
PQXX_CHECK(not extractor, "Stream did not end.");

// Of course we can't stream a non-null value into a nullptr field.
pqxx::stream_from ex2{tx, pqxx::from_query, "SELECT 1"};
auto ex2{pqxx::stream_from::query(tx, "SELECT 1")};
std::tuple<std::nullptr_t> null_tup;
try
{
Expand Down Expand Up @@ -159,8 +159,8 @@ template<template<typename...> class O>
void test_optional(pqxx::connection &connection)
{
pqxx::work tx{connection};
pqxx::stream_from extractor{
tx, pqxx::from_query, "SELECT * FROM stream_from_test ORDER BY number0"};
auto extractor{pqxx::stream_from::query(
tx, "SELECT * FROM stream_from_test ORDER BY number0")};
PQXX_CHECK(extractor, "stream_from failed to initialize");

std::tuple<int, O<std::string>, O<int>, O<ipv4>, O<std::string>, O<bytea>>
Expand Down
3 changes: 1 addition & 2 deletions test/unit/test_transaction_focus.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ namespace
{
auto make_focus(pqxx::dbtransaction &tx)
{
return pqxx::stream_from{
tx, pqxx::from_query, "SELECT * from generate_series(1, 10)"};
return pqxx::stream_from::query(tx, "SELECT * from generate_series(1, 10)");
}


Expand Down

0 comments on commit c0c25ed

Please sign in to comment.