Trait sqlx::FromRow

source ·
pub trait FromRow<'r, R>: Sizedwhere
    R: Row,{
    // Required method
    fn from_row(row: &'r R) -> Result<Self, Error>;
}
Expand description

A record that can be built from a row returned by the database.

In order to use query_as the output type must implement FromRow.

Derivable

This trait can be derived by SQLx for any struct. The generated implementation will consist of a sequence of calls to Row::try_get using the name from each struct field.

#[derive(sqlx::FromRow)]
struct User {
    id: i32,
    name: String,
}

Field attributes

Several attributes can be specified to customize how each column in a row is read:

rename

When the name of a field in Rust does not match the name of its corresponding column, you can use the rename attribute to specify the name that the field has in the row. For example:

#[derive(sqlx::FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(rename = "description")]
    about_me: String
}

Given a query such as:

SELECT id, name, description FROM users;

will read the content of the column description into the field about_me.

rename_all

By default, field names are expected verbatim (with the exception of the raw identifier prefix r#, if present). Placed at the struct level, this attribute changes how the field name is mapped to its SQL column name:

#[derive(sqlx::FromRow)]
#[sqlx(rename_all = "camelCase")]
struct UserPost {
    id: i32,
    // remapped to "userId"
    user_id: i32,
    contents: String
}

The supported values are snake_case (available if you have non-snake-case field names for some reason), lowercase, UPPERCASE, camelCase, PascalCase, SCREAMING_SNAKE_CASE and kebab-case. The styling of each option is intended to be an example of its behavior.

default

When your struct contains a field that is not present in your query, if the field type has an implementation for Default, you can use the default attribute to assign the default value to said field. For example:

#[derive(sqlx::FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(default)]
    location: Option<String>
}

Given a query such as:

SELECT id, name FROM users;

will set the value of the field location to the default value of Option<String>, which is None.

Moreover, if the struct has an implementation for Default, you can use the default`` attribute at the struct level rather than for each single field. If a field does not appear in the result, its value is taken from the Default` implementation for the struct. For example:

#[derive(Default, sqlx::FromRow)]
#[sqlx(default)]
struct Options {
    option_a: Option<i32>,
    option_b: Option<String>,
    option_c: Option<bool>,
}

For a derived Default implementation this effectively populates each missing field with Default::default(), but a manual Default implementation can provide different placeholder values, if applicable.

This is similar to how #[serde(default)] behaves.

flatten

If you want to handle a field that implements FromRow, you can use the flatten attribute to specify that you want it to use FromRow for parsing rather than the usual method. For example:

#[derive(sqlx::FromRow)]
struct Address {
    country: String,
    city: String,
    road: String,
}

#[derive(sqlx::FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(flatten)]
    address: Address,
}

Given a query such as:

SELECT id, name, country, city, road FROM users;

This field is compatible with the default attribute.

skip

This is a variant of the default attribute which instead always takes the value from the Default implementation for this field type ignoring any results in your query. This can be useful, if some field does not satifisfy the trait bounds (i.e. sqlx::decode::Decode, sqlx::type::Type), in particular in case of nested structures. For example:

#[derive(sqlx::FromRow)]
struct Address {
    user_name: String,
    street: String,
    city: String,
}

#[derive(sqlx::FromRow)]
struct User {
    name: String,
    #[sqlx(skip)]
    addresses: Vec<Address>,
}

Then when querying into User, only name needs to be set:

let user: User = sqlx::query_as("SELECT name FROM users")
   .fetch_one(&mut some_connection)
   .await?;

`Default` for `Vec<Address>` is an empty vector.
assert!(user.addresses.is_empty());

Manual implementation

You can also implement the FromRow trait by hand. This can be useful if you have a struct with a field that needs manual decoding:

use sqlx::{FromRow, sqlite::SqliteRow, sqlx::Row};
struct MyCustomType {
    custom: String,
}

struct Foo {
    bar: MyCustomType,
}

impl FromRow<'_, SqliteRow> for Foo {
    fn from_row(row: &SqliteRow) -> sqlx::Result<Self> {
        Ok(Self {
            bar: MyCustomType {
                custom: row.try_get("custom")?
            }
        })
    }
}
try_from

When your struct contains a field whose type is not matched with the database type, if the field type has an implementation TryFrom for the database type, you can use the try_from attribute to convert the database type to the field type. For example:

#[derive(sqlx::FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(try_from = "i64")]
    bigIntInMySql: u64
}

Given a query such as:

SELECT id, name, bigIntInMySql FROM users;

In MySql, BigInt type matches i64, but you can convert it to u64 by try_from.

json

If your database supports a JSON type, you can leverage #[sqlx(json)] to automatically integrate JSON deserialization in your FromRow implementation using serde.

#[derive(serde::Deserialize)]
struct Data {
    field1: String,
    field2: u64
}

#[derive(sqlx::FromRow)]
struct User {
    id: i32,
    name: String,
    #[sqlx(json)]
    metadata: Data
}

Given a query like the following:

SELECT
    1 AS id,
    'Name' AS name,
    JSON_OBJECT('field1', 'value1', 'field2', 42) AS metadata

The metadata field will be deserialized used its serde::Deserialize implementation:

User {
    id: 1,
    name: "Name",
    metadata: Data {
        field1: "value1",
        field2: 42
    }
}

Required Methods§

source

fn from_row(row: &'r R) -> Result<Self, Error>

Object Safety§

This trait is not object safe.

Implementations on Foreign Types§

source§

impl<'r, R> FromRow<'r, R> for ()where R: Row,

source§

impl<'r, R, T1> FromRow<'r, R> for (T1,)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2> FromRow<'r, R> for (T1, T2)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3> FromRow<'r, R> for (T1, T2, T3)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4> FromRow<'r, R> for (T1, T2, T3, T4)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5> FromRow<'r, R> for (T1, T2, T3, T4, T5)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T10: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T10: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T11: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T10: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T11: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T12: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T10: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T11: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T12: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T13: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T10: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T11: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T12: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T13: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T14: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T10: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T11: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T12: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T13: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T14: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T15: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

source§

impl<'r, R, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> FromRow<'r, R> for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16)where R: Row, usize: ColumnIndex<R>, T1: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T2: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T3: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T4: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T5: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T6: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T7: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T8: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T9: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T10: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T11: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T12: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T13: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T14: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T15: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>, T16: Decode<'r, <R as Row>::Database> + Type<<R as Row>::Database>,

Implementors§