Go to file
2025-01-23 16:04:47 +08:00
.cargo 修改config.toml使用清华镜像 2024-05-21 14:43:09 +08:00
.vscode 移除文件保存不校验的问题 2024-09-30 15:17:15 +08:00
domain 格式化代码 2024-11-02 19:45:19 +08:00
i18n 格式化代码 2024-11-02 19:45:19 +08:00
library 移除无用日志 2025-01-23 16:04:47 +08:00
macro 优化代码 2024-11-06 10:39:37 +08:00
server 移除无用日志 2024-11-06 14:56:34 +08:00
src 修改main函数 2024-10-29 11:53:33 +08:00
.env 修改数据库链接信息和表结构 2024-09-21 16:09:41 +08:00
.gitignore 修改.gitignore 2024-06-28 17:11:11 +08:00
app.toml 增加google client配置 2025-01-23 11:46:31 +08:00
Cargo.lock 修改google play登录 2025-01-23 11:45:36 +08:00
Cargo.toml 修改google play登录 2025-01-23 11:45:36 +08:00
i18n.csv 修改i18n拼写错误 2024-10-29 11:40:41 +08:00
README.MD 更新readme 2024-10-11 20:52:28 +08:00

todo

  • [*] 使用Extractor方式提取数据包括Body、Query和Path
  • multipart/form-data的实现
  • [*] 参考example中的jwt实现方式移除context对extension的依赖那么language-tag该怎么处理
  • 参考rocket移除参数的元组类型
  • [-] 能否自定义实现宏路由
    • [*] 定向路由的实现
    • [*] 支持多种method的路由
    • 宏路由支持fallback等

note

  • 展开宏cargo expand --manifest-path .\server\Cargo.toml controller::feedback_controller

sqlx type

注意sqlx feature里面time和chrono选择一个即可 https://docs.rs/sqlx/latest/sqlx/postgres/types/index.html

https://sqlx.dev/

sql dynamic query

https://github.com/launchbadge/sqlx/blob/main/FAQ.md#how-can-i-bind-an-array-to-a-values-clause-how-can-i-do-bulk-inserts

use sqlx::{query_builder::QueryBuilder, Execute};

struct Search {
    id: i64,
    username: Option<String>,
    min_age: Option<i8>,
    max_age: Option<i8>,
}

fn search_query(search: Search) -> String {
    let mut query = QueryBuilder::new("SELECT * from users where id = ");
    query.push_bind(search.id);

    if let Some(username) = search.username {
        query.push(" AND username = ");
        query.push_bind(username);
    }

    if let Some(min_age) = search.min_age {
        query.push(" AND age > ");
        query.push_bind(min_age);
    }

    if let Some(max_age) = search.max_age {
        query.push(" AND age < ");
        query.push_bind(max_age);
    }

    query.build().sql().into()
}

fn main() {
    dbg!(search_query(Search {
        id: 12,
        username: None,
        min_age: None,
        max_age: None,
    })); // "SELECT * from users where id = $1"
    dbg!(search_query(Search {
        id: 12,
        username: Some("Bob".into()),
        min_age: None,
        max_age: None,
    })); // "SELECT * from users where id = $1 AND username = $2"
    dbg!(search_query(Search {
        id: 12,
        username: Some("Bob".into()),
        min_age: Some(10),
        max_age: Some(70),
    })); // "SELECT * from users where id = $1 AND username = $2 AND age > $3 AND age < $4"
}
use sqlx::{Execute, MySql, QueryBuilder};

struct User {
    id: i32,
    username: String,
    email: String,
    password: String,
}

// The number of parameters in MySQL must fit in a `u16`.
const BIND_LIMIT: usize = 65535;

// This would normally produce values forever!
let users = (0..).map(|i| User {
    id: i,
    username: format!("test_user_{i}"),
    email: format!("test-user-{i}@example.com"),
    password: format!("Test!User@Password#{i}"),
});

let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
    // Note the trailing space; most calls to `QueryBuilder` don't automatically insert
    // spaces as that might interfere with identifiers or quoted strings where exact
    // values may matter.
    "INSERT INTO users(id, username, email, password) "
);

// Note that `.into_iter()` wasn't needed here since `users` is already an iterator.
query_builder.push_values(users.take(BIND_LIMIT / 4), |mut b, user| {
    // If you wanted to bind these by-reference instead of by-value,
    // you'd need an iterator that yields references that live as long as `query_builder`,
    // e.g. collect it to a `Vec` first.
    b.push_bind(user.id)
        .push_bind(user.username)
        .push_bind(user.email)
        .push_bind(user.password);
});

let mut query = query_builder.build();

// You can then call `query.execute()`, `.fetch_one()`, `.fetch_all()`, etc.
// For the sake of demonstration though, we're just going to assert the contents
// of the query.

// These are methods of the `Execute` trait, not normally meant to be called in user code.
let sql = query.sql();
let arguments = query.take_arguments().unwrap();

assert!(sql.starts_with(
    "INSERT INTO users(id, username, email, password) VALUES (?, ?, ?, ?), (?, ?, ?, ?)"
));

assert!(sql.ends_with("(?, ?, ?, ?)"));

// Not a normally exposed function, only used for this doctest.
// 65535 / 4 = 16383 (rounded down)
// 16383 * 4 = 65532
assert_eq!(arguments.len(), 65532);