tursodatabase / tursodatabase/libsql

Joint row deserialization into structs

Open
#1,314 2 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C
Stars
17.2k
Forks
531
Avg merge
1h 12m
Merged PRs (30d)
1

Description

I have this common use case where I join two tables and I want to deserialize a row into separate structs. However, each row cannot be easily deserialized into separate structs via from_row.

#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Default)]
pub struct User {
  pub id: i32,
  pub date: DateTime<Utc>,
  pub group_id: i32,
}

#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Default)]
pub struct Group {
  pub id: i32,
  pub name: String,
}

The query is like

let rows = db_conn
    .query(
      "SELECT users.*, groups.*
        FROM users
        JOIN groups ON users.group_id = groups.id
        WHERE users.user_id = ?1 LIMIT ?2
    ",
      params![user_id.clone(), 10],
    )
    .await?;

while let Some(row) = rows.next().await? {
	// there's no such thing:
	let (users, group) = from_row<(User, Group)>(&row)?;
}

I have to do things like the following to be able to convert a Row into separate structs:


#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Default)]
pub struct UserWithGroup {
  pub user: User,
  pub group: Group,
}

// Implement from_row for UserWithGroup to deserialize from a database row
impl UserWithGroup {
  pub fn from_row<'de>(row: &'de Row) -> Result<UserWithGroup, DeError> {
    return Ok(Self {
      user: User {
        id: row.get(0).expect("id"),
        date: DateTime::deserialize(
          row.get_value(1).expect("date").into_deserializer(),
        )?,
        group_id: row.get(2).expect("group_id"),
      },
      group: Group {
        id: row.get(3).expect("group_id"),
        name: row.get(4).expect("name"),
      },
    });
  }
}

To be able to do something like

while let Some(row) = rows.next().await? {
	let users_with_group = UsersWithGroup::from_row(&row)?;
}

Is there a way to support from_row for the JOIN use cases maybe via tuples so that this manual work is not needed anymore?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing from_row and Row APIs used with rows.next() in the Rust database interface, then trace how joined-result columns are exposed. Done means a joined row can be converted into separate User and Group values through the requested tuple-style API without the manual UserWithGroup mapping.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, sqlite
Domain
databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.