2个不稳定版本
使用旧Rust 2015
0.1.0 | 2018年2月10日 |
---|---|
0.0.1 | 2015年12月30日 |
在数据库接口中排名第1038
47KB
717 行
TQL
:source-highlighter: pygments
编译时ORM,受Django ORM启发,用Rust编写。Tql作为过程宏实现,甚至可以在Rust的稳定版本上工作(查看此示例以了解如何在稳定版本上使用tql)。
此库处于alpha阶段:它尚未经过彻底测试,其API可能随时更改。
需求
目前,tql
仅支持PostgreSQL
数据库(将来将支持更多数据库)。因此,您需要安装PostgreSQL
才能使用此crate。
用法
首先,将以下内容添加到您的Cargo.toml
[source,toml]
[dependencies]
chrono = "^0.4.0"
tql = { git = "https://github.com/antoyo/tql" }
tql_macros = { git = "https://github.com/antoyo/tql" }
[dependencies.postgres]
features = ["with-chrono"]
version = "^0.15.1"
(如果您不希望在模型中使用日期和时间类型,可以删除chrono
相关内容。)
接下来,将以下内容添加到您的crate中
[source,rust]
#![feature(proc_macro)]
extern crate chrono;
extern crate postgres;
extern crate tql;
#[macro_use]
extern crate tql_macros;
use postgres::{Connection, TlsMode};
use tql::PrimaryKey;
use tql_macros::sql;
然后,创建您的模型
[source,rust]
use chrono::DateTime;
use chrono::offset::Utc;
#[derive(SqlTable)]
struct Model {
id: PrimaryKey,
text: String,
date_added: DateTime<Utc>,
// …
}
接下来,创建您的连接访问器
[source,rust]
fn get_connection() -> Connection {
Connection::connect("postgres://test:test@localhost/database", TlsMode::None).unwrap()
}
最后,我们可以使用sql!
宏来执行SQL查询
[source,rust]
fn main() {
let connection = get_connection();
// We first create the table.
// (You might not want to execute this query every time.)
let _ = sql!(Model.create());
// Insert a row in the table.
let text = String::new();
let id = sql!(Model.insert(text = &text, date_added = Utc::now())).unwrap();
// Update a row.
let result = sql!(Model.get(id).update(text = "new-text"));
// Delete a row.
let result = sql!(Model.get(id).delete());
// Query some rows from the table:
// get the last 10 rows sorted by date_added descending.
let items = sql!(Model.sort(-date_added)[..10]);
}
sql!()
宏默认使用标识符connection
。
查看以下表格以获取更多示例。
在稳定Rust上使用
如果您想在稳定Rust上使用tql
,需要进行一些更改才能正常工作
首先,删除以下行
[source,rust]
#![feature(proc_macro)]
// …
use tql_macros::sql;
并在extern crate tql
之前添加以下行
[source,rust]
#[macro_use]
现在文件的开头如下所示
[source,rust]
extern crate chrono;
extern crate postgres;
#[macro_use]
extern crate tql;
#[macro_use]
extern crate tql_macros;
use postgres::{Connection, TlsMode};
use tql::PrimaryKey;
最后,通过更新tql
依赖项来禁用unstable
功能
[source,toml]
tql = { git = "https://github.com/antoyo/tql", default-features = false }
通过这个小小的更改,我们可以像以前一样使用sql!()
宏。
为什么不是总是使用稳定版本?
过程宏目前不支持在稳定版本上特定位置发出错误,因此使用此版本时,您将得到一些不太有用的错误,如下面的输出所示
[source]
error[E0308]: mismatched types
--> src/main.rs:47:18
|
47 | let result = sql!(Model.insert(text = text, date_added = Utc::now(), done = false));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &str, found struct `std::string::String`
|
= note: expected type `&str`
found type `std::string::String`
= help: try with `&sql!(Model.insert(text = text, date_added = Utc::now(), done = false))`
= note: this error originates in a macro outside of the current crate
当使用Rust的夜间版本时,你会得到这样的错误提示。
[source]
error[E0308]: mismatched types
--> examples/todo.rs:49:46
|
49 | let result = sql!(Model.insert(text = text, date_added = Utc::now(), done = false));
| ^^^^
| |
| expected &str, found struct `std::string::String`
| help: consider borrowing here: `&text`
|
= note: expected type `&str`
found type `std::string::String`
因此,一个好的工作流程是在夜间版本上进行开发,然后使用稳定版发布。这样,你可以两全其美:你可以得到漂亮的错误提示,并且可以使用编译器的稳定版进行部署。这根本不是问题,因为当你准备部署时,你不应该有编译器错误(你仍然可以查看错误)。
注意:使用以下命令编译以获得更好的错误信息:RUSTFLAGS "--cfg procmacro2_semver_exempt"
语法表
左侧显示生成的SQL,右侧显示你可以与tql
一起使用的语法。
[cols="1a,1a", options="header"] |=== | SQL | Rust
| [source, sql]
SELECT * FROM Table
| [source, rust]
Table.all()
| [source, sql]
SELECT * FROM Table WHERE field1 = 'value1'
| [source, rust]
Table.filter(field1 == "value1")
| [source, sql]
SELECT * FROM Table WHERE primary_key = 42
| [source, rust]
Table.get(42)
// Shortcut for:
Table.filter(primary_key == 42)[0..1];
| [source, sql]
SELECT * FROM Table WHERE field1 = 'value1'
| [source, rust]
Table.get(field1 == "value1")
// Shortcut for:
Table.filter(field1 == "value1")[0..1];
| [source, sql]
SELECT * FROM Table WHERE field1 = 'value1' AND field2 < 100
| [source, rust]
Table.filter(field1 == "value1" && field2 < 100)
| [source, sql]
SELECT * FROM Table WHERE field1 = 'value1' OR field2 < 100
| [source, rust]
Table.filter(field1 == "value1" \|\| field2 < 100)
| [source, sql]
SELECT * FROM Table ORDER BY field1
| [source, rust]
Table.sort(field1)
| [source, sql]
SELECT * FROM Table ORDER BY field1 DESC
| [source, rust]
Table.sort(-field1)
| [source, sql]
SELECT * FROM Table LIMIT 0, 20
| [source, rust]
Table[0..20]
| [source, sql]
SELECT * FROM Table
WHERE field1 = 'value1'
AND field2 < 100
ORDER BY field2 DESC
LIMIT 10, 20
| [source, rust]
Table.filter(field1 == "value1" && field2 < 100)
.sort(-field2)[10..20]
| [source, sql]
INSERT INTO Table(field1, field2) VALUES('value1', 55)
| [source, rust]
Table.insert(field1 = "value1", field2 = 55)
| [source, sql]
UPDATE Table SET field1 = 'value1', field2 = 55 WHERE id = 1
| [source, rust]
Table.get(1).update(field1 = "value1", field2 = 55);
// or
Table.filter(id == 1).update(field1 = "value1", field2 = 55);
| [source, sql]
DELETE FROM Table WHERE id = 1
| [source, rust]
Table.get(1).delete();
// ou
Table.filter(id == 1).delete()
| [source, sql]
SELECT AVG(field2) FROM Table
| [source, rust]
Table.aggregate(avg(field2))
| [source, sql]
SELECT AVG(field1) FROM Table1 GROUP BY field2
| [source, rust]
Table1.values(field2).annotate(avg(field1))
| [source, sql]
SELECT AVG(field1) as average FROM Table1
GROUP BY field2
HAVING average > 5
| [source, rust]
Table1.values(field2).annotate(average = avg(field1))
.filter(average > 5)
| [source, sql]
SELECT AVG(field1) as average FROM Table1
WHERE field1 < 10
GROUP BY field2
HAVING average > 5
| [source, rust]
Table1.filter(field1 < 10).values(field2)
.annotate(average = avg(field1)).filter(average > 5)
| [source, sql]
SELECT Table1.field1, Table2.field1 FROM Table1
INNER JOIN Table2 ON Table1.pk = Table2.fk
| [source, rust]
#[derive(SqlTable)]
struct Table1 {
pk: PrimaryKey,
field1: i32,
}
#[derive(SqlTable)]
struct Table2 {
field1: i32,
fk: ForeignKey<Table1>,
}
Table1.all().join(Table2)
| [source, sql]
SELECT * FROM Table1 WHERE YEAR(date) = 2015
| [source, rust]
Table1.filter(date.year() == 2015)
| [source, sql]
SELECT * FROM Table1 WHERE INSTR(field1, 'string') > 0
| [source, rust]
Table1.filter(field1.contains("string"))
| [source, sql]
SELECT * FROM Table1 WHERE field1 LIKE 'string%'
| [source, rust]
Table1.filter(field1.starts_with("string"))
| [source, sql]
SELECT * FROM Table1 WHERE field1 LIKE '%string'
| [source, rust]
Table1.filter(field1.ends_with("string"))
| [source, sql]
SELECT * FROM Table1 WHERE field1 IS NULL
| [source, rust]
Table1.filter(field1.is_none())
| [source, sql]
SELECT * FROM Table1 WHERE field1 REGEXP BINARY '\^[a-d]'
| [source, rust]
Table1.filter(field1.regex(r"\^[a-d]"))
| [source, sql]
SELECT * FROM Table1 WHERE field1 REGEXP '\^[a-d]'
| [source, rust]
Table1.filter(field1.iregex(r"\^[a-d]"))
| [source, sql]
CREATE TABLE IF NOT EXISTS Table1 (
pk INTEGER NOT NULL AUTO_INCREMENT,
field1 INTEGER,
PRIMARY KEY (pk)
)
| [source, rust]
#[derive(SqlTable)]
struct Table1 {
pk: PrimaryKey,
field1: i32,
}
Table1.create()
依赖
~2.2–6.5MB
~136K SLoC