Skip to content

Add a Row-like interface to any PostgreSQL composite type #565

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

alexwl
Copy link

@alexwl alexwl commented Jan 31, 2020

It can be useful to be able to get fields of a composite type without the need to derive FromSql for a structure (#366).

This PR adds a new type CompositeType that implements FromSql and has the same methods as Row.

Example:

create table users (
  id               serial primary key,
  name             text
);
create table posts (
  id               serial primary key,
  author_id        integer not null references users(id),
  title            text,
  content          text
);
let query = "SELECT users.*,ARRAY_REMOVE(ARRAY_AGG(posts),NULL) as posts FROM users LEFT JOIN posts ON posts.author_id = users.id GROUP BY users.id";
let stmt = client.prepare(query).await?;
let rows: Vec<Row> = client.query(&stmt, &[]).await?;
for user_with_posts in rows {
    let user_name = user_with_posts.get::<_,&str>("name");
    // ...
    let user_posts = user_with_posts.get::<_,Vec<CompositeType>>("posts");
    for post in user_posts {
        let post_title = post.get::<_,&str>("title");
        let post_content = post.get::<_,&str>("content");
        // ...
    }
}

The binary format of a composite type is different from the format of a DataRow (there is an OID before each length/value pair), so I added a type parameter to DataRowRanges to make FallibleIterator for ranges usable for both cases:
https://github.com/alexwl/rust-postgres/blob/aa4b5547e3bf13e112ae90dd919b0ac70d67ebaa/postgres-protocol/src/message/backend.rs#L550-L574

This adds a new type CompositeType that implements FromSql and has the same interface as Row.
@@ -531,11 +532,12 @@ pub struct DataRowBody {

impl DataRowBody {
#[inline]
pub fn ranges(&self) -> DataRowRanges<'_> {
pub fn ranges(&self) -> DataRowRanges<'_, DataRow> {
Copy link
Owner

Choose a reason for hiding this comment

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

This module is specifically for parsing the backend protocol messages. I'd rather have composite support added in the types module.

}

impl<'a> CompositeType<'a> {
pub(crate) fn new(
Copy link
Owner

Choose a reason for hiding this comment

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

It seems like this can just be inlined in to the FromSql implementation.

Move code from CompositeType::new to FromSql::from_sql.
Move support for composite types from message/backend.rs to types/mod.rs.
@alexwl
Copy link
Author

alexwl commented Feb 1, 2020

I moved the code from CompositeType::new to FromSql::from_sql and moved the iterator over the fields of a composite type to postgres-protocol/src/types/mod.rs.

@runfalk
Copy link
Contributor

runfalk commented Mar 27, 2020

Is there something blocking this? It is something I'm quite interested in myself.

@alexwl
Copy link
Author

alexwl commented Mar 28, 2020

I'm also still interested in this. I can update the PR if necessary.

@mpalmer
Copy link

mpalmer commented Jun 13, 2024

I've rebased this PR against current master, and it applied successfully (patch seemed to find the right offsets). I'm now using it in a project, and so far it seems to working great, so I'd be 👍 for merge. One thing that seemed a bit odd was how CompositeType was in tokio-postgres, rather than, say, postgres-types, as I can't see any async-specific code in the implementation. (ETA: merged code is at https://github.com/mpalmer/rust-postgres branch pr565 if anyone wants to use it)

@phillipleblanc
Copy link

If you need this before its merged, you can also just copy the structs from this PR into your codebase to use it without needing to fork this library. An example of this can be found here: https://github.com/spiceai/spiceai/blob/trunk/crates/arrow_sql_gen/src/postgres/composite.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants