#from-row #rusqlite #sqlite #mapper

rusqlite-from-row-derive

rusqlite-from-row的内部proc-macro crate

6个版本

0.2.4 2024年5月1日
0.2.3 2024年3月14日
0.2.2 2024年1月2日
0.2.1 2023年11月29日
0.1.0 2023年5月28日

#5 in #from-row

每月下载量 48次
用于 rusqlite-from-row

自定义许可

18KB
381

rusqlite-from-row

FromRow派生以生成结构体与rusqlite行之间的映射。

[dependencies]
rusqlite_from_row = "0.2.4"

用法

派生FromRow并执行查询以选择具有相同名称和类型的列。

use rusqlite_from_row::FromRow;

#[derive(FromRow)]
struct Todo {
    todo_id: i32,
    text: String,
    author_id: i32,
}

let row = connection.query_row("SELECT todo_id, text, author_id FROM todos", [], Todo::try_from_row).unwrap();

嵌套、连接和平铺

您可能希望将两个表之间的连接表示为嵌套结构体。这可以通过在嵌套字段上使用#[from_row(flatten)]来实现。这将委托该字段的创建到具有相同行的FromRow::from_row,而不是到FromSql

由于表在连接时可能存在命名冲突,您可以指定一个prefix = ""来唯一检索列。此前缀应与在select中重命名列时指定的前缀相匹配,例如select <column> as <prefix><column>。支持嵌套前缀。

还可以使用#[from_row(prefix)]而不带值。在这种情况下,将使用下划线后的字段名。

可以通过将展开的类型包装在Option中来实现外部连接。FromRowOption实现将仍然需要所有列都存在,但如果所有列都是SQL null值,则将产生一个None

use rusqlite_from_row::FromRow;

#[derive(FromRow)]
struct Todo {
    id: i32,
    name: String,
    text: String,
    #[from_row(flatten, prefix = "user_")]
    author: User
    #[from_row(flatten, prefix)]
    editor: User
}

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

// Rename all `User` fields to have `user_` or `editor_` prefixes.
let row = client
    .query_one(
        "
    SELECT 
        t.id, 
        t.name, 
        t.text, 
        u.name as user_name, 
        u.id as user_id,
        e.name as editor_name,
        e.id as editor_id
    FROM 
        todos t 
    JOIN 
        user u ON t.author_id = u.id
    JOIN
        user e ON t.editor_id = e.id
        ",
        [],
        Todo::try_from_row,
    )
    .unwrap();

重命名和转换

如果一个结构体包含一个名称与SQL列名不同的字段,可以使用 #[from_row(rename = "..")] 属性。

通常情况下,如果您有一个自定义包装类型,例如 struct DbId(i32),则需要实现 FromSql 才能在查询中使用它。一个简单的替代方法是实现 From<i32>TryFrom<i32> 用于 DbId,并在字段上添加 #[from_row(from = "i32")]#[from_row(try_from = "i32")]

这将委托SQL转换到 <i32 as FromSql>,然后将其转换为 DbId


use rusqlite_from_row::FromRow;

struct DbId(i32);

impl From<i32> for DbId {
    fn from(value: i32) -> Self {
        Self(value)
    }
}

#[derive(FromRow)]
struct Todo {
    // If the sqlite column is named `todo_id`.
    #[from_row(rename = "todo_id", from = "i32")]
    id: i32,
    // If the sqlite column is `TEXT`, it will be decoded to `String`,
    // using `FromSql` and then converted to `Vec<u8>` using `std::convert::From`.
    #[from_row(from = "String")]
    todo: Vec<u8>
}

依赖关系

~230–670KB
~16K SLoC