19个不稳定版本 (7个破坏性更新)

新功能 0.11.0 2024年8月18日
0.10.0 2024年5月14日
0.9.0 2023年11月16日
0.8.0 2023年10月25日
0.0.0 2023年10月9日

654数据库接口

Download history 142/week @ 2024-05-10 27/week @ 2024-05-17 4/week @ 2024-05-24 13/week @ 2024-05-31 14/week @ 2024-06-07 11/week @ 2024-06-14 2/week @ 2024-06-21 4/week @ 2024-06-28 7/week @ 2024-07-05 5/week @ 2024-07-12 4/week @ 2024-07-19 10/week @ 2024-07-26 4/week @ 2024-08-02 133/week @ 2024-08-16

每月147次 下载

MIT/Apache

38KB
232

Exemplar

rusqlite的样板代码消除器。

入门指南

一窥你可以做什么

#[derive(Debug, PartialEq, Model)]
#[table("users")]
#[check("../tests/schema.sql")]
struct User {
   username: String,
   #[bind(bind_path)]
   #[extr(extr_path)]
   home_dir: PathBuf,
   #[column("pwd")]
   password: Vec<u8>,
}
 
fn main() -> Result<()> {
    let conn = Connection::open_in_memory()?;
 
    conn.execute_batch(
        include_str!("../tests/schema.sql")
    )?;
 
    let alice = User {
        username: "Alice".to_owned(),
        home_dir: "/var/home/alice".into(),
        password: b"hunter2".to_vec()
    };
 
    let bob = User {
        username: "Bob".to_owned(),
        home_dir: "/var/home/robert".into(),
        password: b"password".to_vec()
    };
 
    alice.insert(&conn)?;
    bob.insert(&conn)?;
 
    let mut stmt = conn.prepare("
        SELECT * FROM users ORDER BY username ASC
    ")?;
    
    let mut iter = stmt.query_and_then([], User::from_row)?;
 
    assert_eq!(alice, iter.next().unwrap()?);
    assert_eq!(bob, iter.next().unwrap()?);
 
    Ok(())
}

Exemplar基于Model特质,该特质有自己的

  • 查看上述的文档以开始。
  • 对于在模型中处理enum,请参阅sql_enum宏。
  • 对于与"匿名"记录类型一起工作,请查看record宏。

功能

  • 与原始SQL一起工作,而不是与之对抗。
  • 轻量级,零成本API。
    • Exemplar的大部分内容围绕Model特质展开,该特质在运行时被内联和单态化。生成的代码大致是你手动使用纯rusqlite时编写的。
    • 设计为即插即用;尽可能重用rusqlite的现有类型,包括其Result类型别名。
    • 支持任何可以Derefrusqlite::Connection的类型,例如事务或池连接。
  • 可选测试推导,以防止数据库模式和Rust模型类型之间的漂移。
  • 用于处理与SQL兼容的enum和映射到特定查询的"匿名"记录类型的宏。
  • 在运行时对dyn Model进行反射/工作的某些能力。

如果你只需要使用sqlite进行一些Rust数据的CRUD操作,而不需要完整的ORM或企业级DBMS,那么Exemplar适合你!

常见问题解答

"Exemplar不能做什么?"

一些关键事项

  • 模式生成和管理。示例程序明确不是ORM,且在没有陷入ORM领域的情况下,很难表示外键和迁移等概念。
    • 如果您“必须”使用它,请查看dieselsqlx/seaorm,它们都支持SQLite。
  • 查询生成(不包括INSERT。)
  • 接口可移植性。仅支持rusqlite

"它是否非常快?"

是的。在我的机器上(根据这些基准测试),Exemplar可以

  • 在~600纳秒内插入一个非平凡的模型类型(每秒1.6百万行)
  • 查询并重建相同的类型在~9微秒内(每秒111,000行,使用SELECT * LIMIT 1

显然,这种速度的功劳应归于SQLite和rusqlite的开发者,但我可以自信地说,我没有减慢事情的速度!

"这与serde-rusqlite相比如何?"

serde_rusqlite是一个巧妙的技巧,但它仍然涉及太多的扭曲和样板代码——这就是为什么我创建了Exemplar。

我试图解决的一些痛点

  • 需要分配和操作一个String列名切片,以有效地反序列化行——这可能是由于serde的限制?
    • Exemplar静态地知道应期望哪些列,因此from_row不需要额外的输入,也不进行任何多余的分配。
  • 无字段的enum的设计选择——它们被无效率地序列化为TEXT而不是INTEGER。这对于调试来说很方便,但我认为更快的选项应该是Exemplar的默认设置。
  • to_params_named(&row1).unwrap().to_slice().as_slice()
    • 等同于在Exemplar中row1.insert(&conn)row1.insert_with(&stmt)
  • 编译和运行时都会出现一般的serde开销。
    • 基准测试显示,与Exemplar相比,serde_rusqlite在插入操作上慢了约25%。
    • 检索操作同样快速,可能是因为最终转换步骤与查询计算和I/O相比微不足道。

致谢

  • rusqlite,为这个库提供了基础。
  • David Tolnay,为他各种各样的proc宏咒语crate。

依赖关系

~23MB
~434K SLoC