diff --git a/NEWS b/NEWS index 2b92cce98..4242920fc 100644 --- a/NEWS +++ b/NEWS @@ -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? diff --git a/include/pqxx/doc/streams.md b/include/pqxx/doc/streams.md index 639d49331..96edac939 100644 --- a/include/pqxx/doc/streams.md +++ b/include/pqxx/doc/streams.md @@ -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 row; while (stream >> row) process(row); diff --git a/include/pqxx/internal/ignore-deprecated-post.hxx b/include/pqxx/internal/ignore-deprecated-post.hxx index fe16003b9..454f2f638 100644 --- a/include/pqxx/internal/ignore-deprecated-post.hxx +++ b/include/pqxx/internal/ignore-deprecated-post.hxx @@ -5,5 +5,5 @@ #endif // __GNUC__ #ifdef _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #endif diff --git a/include/pqxx/internal/ignore-deprecated-pre.hxx b/include/pqxx/internal/ignore-deprecated-pre.hxx index 661fd0281..8fb650623 100644 --- a/include/pqxx/internal/ignore-deprecated-pre.hxx +++ b/include/pqxx/internal/ignore-deprecated-pre.hxx @@ -18,6 +18,6 @@ #endif // __GNUC__ #ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4996) +# pragma warning(push) +# pragma warning(disable : 4996) #endif diff --git a/include/pqxx/stream_from.hxx b/include/pqxx/stream_from.hxx index a482b7105..7d0596601 100644 --- a/include/pqxx/stream_from.hxx +++ b/include/pqxx/stream_from.hxx @@ -70,9 +70,12 @@ public: using raw_line = std::pair>, 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 @@ -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 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 stream_from( transaction_base &tx, from_table_t, std::string_view table, @@ -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; @@ -156,6 +177,7 @@ public: template stream_from &operator>>(std::variant &) = delete; + // TODO: Hide this from the public. /// Iterate over this stream. Supports range-based "for" loops. /** Produces an input iterator over the stream. * diff --git a/test/unit/test_stream_from.cxx b/test/unit/test_stream_from.cxx index 513e54555..b798ad5ac 100644 --- a/test/unit/test_stream_from.cxx +++ b/test/unit/test_stream_from.cxx @@ -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 got_tuple; @@ -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 null_tup; try { @@ -159,8 +159,8 @@ template 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, O, O, O, O> diff --git a/test/unit/test_transaction_focus.cxx b/test/unit/test_transaction_focus.cxx index 9e4360005..48fdfdd3f 100644 --- a/test/unit/test_transaction_focus.cxx +++ b/test/unit/test_transaction_focus.cxx @@ -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)"); }