Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#841: Support parsing a field as an SQL array. #854

Merged
merged 4 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Another fix to the readthedocs documentation build. (#845)
- Work around CMake 3.30 renaming one of its functions. (#851)
- Remove obscure deprecated `stream_to` constructor that never worked. (#853)
- Support reading a field as an SQL array using `as_sql_array()`. (#841)
7.9.1
- Fix bad conversion of array of empty strings to string. (#816)
- Move `[[likely]]` feature check back to compile time, to speed up configure.
Expand Down
12 changes: 7 additions & 5 deletions include/pqxx/array.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,11 @@ private:
"Malformed array: does not end in the right number of '}'."};
}

explicit array(std::string_view data, pqxx::internal::encoding_group enc)
// Allow fields to construct arrays passing the encoding group.
// Couldn't make this work through a call gate, thanks to the templating.
friend class ::pqxx::field;

array(std::string_view data, pqxx::internal::encoding_group enc)
{
using group = pqxx::internal::encoding_group;
switch (enc)
Expand Down Expand Up @@ -502,10 +506,8 @@ private:
};


/// Low-level array parser.
/** @warning This is not a great API. Something nicer is on the way.
*
* Use this to read an array field retrieved from the database.
/// Low-level parser for C++ arrays. @deprecated Use @ref pqxx::array instead.
/** Clunky old API for parsing SQL arrays.
*
* @warning This parser will only work reliably if your client encoding is
* UTF-8, ASCII, or a "safe ASCII superset" (such as the EUC encodings) where
Expand Down
17 changes: 17 additions & 0 deletions include/pqxx/field.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,30 @@ public:
return as<O<T>>();
}

/// Read SQL array contents as a @ref pqxx::array.
template<typename ELEMENT, auto... ARGS>
array<ELEMENT, ARGS...> as_sql_array() const
{
using array_type = array<ELEMENT, ARGS...>;

// There's no such thing as a null SQL array.
if (is_null())
internal::throw_null_conversion(type_name<array_type>);
else
return array_type{this->view(), this->m_home.m_encoding};
}

/// Parse the field as an SQL array.
/** Call the parser to retrieve values (and structure) from the array.
*
* Make sure the @ref result object stays alive until parsing is finished. If
* you keep the @ref row of `field` object alive, it will keep the @ref
* result object alive as well.
*/
[[deprecated(
Copy link
Contributor

@fallenworld1 fallenworld1 Jun 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this deprecation. Looks like pqxx::array doesn't allow move and extraction to an external structure, which could be useful. Otherwise looks great

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I suppose we could consider supporting moves, if we find a good use for them. But when are they really worthwhile? Perhaps if the array elements were of a custom time which in turn contained an array, or something like that.

Same consideration for extraction to an external structure: when is that helpful? You can copy elements right now. Or just keep the pqxx::array object as the basic storage for that data.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fallenworld1 for now if you don't mind I think I'll just merge this, and then make any incremental improvements as needed.

"Avoid pqxx::array_parser. "
"Instead, use as_sql_array() to convert to pqxx::array."
)]]
array_parser as_array() const & noexcept
{
return array_parser{c_str(), m_home.m_encoding};
Expand Down
15 changes: 15 additions & 0 deletions test/unit/test_array.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,20 @@ void test_array_iterates_in_row_major_order()
}


void test_as_sql_array()
Fixed Show fixed Hide fixed
Dismissed Show dismissed Hide dismissed
{
pqxx::connection conn;
pqxx::row r;
{
pqxx::work tx{conn};
r = tx.exec1("SELECT ARRAY [5, 4, 3, 2]");
// Connection closes, but we should still be able to parse the array.
}
auto const array{r[0].as_sql_array<int>()};
PQXX_CHECK_EQUAL(array[1], 4, "Got wrong value out of array.");
}


PQXX_REGISTER_TEST(test_empty_arrays);
PQXX_REGISTER_TEST(test_array_null_value);
PQXX_REGISTER_TEST(test_array_double_quoted_string);
Expand All @@ -714,4 +728,5 @@ PQXX_REGISTER_TEST(test_array_parses_multidim_arrays);
PQXX_REGISTER_TEST(test_array_at_checks_bounds);
PQXX_REGISTER_TEST(test_array_iterates_in_row_major_order);
PQXX_REGISTER_TEST(test_array_generate_empty_strings);
PQXX_REGISTER_TEST(test_as_sql_array);
} // namespace
Loading