sqlxplus-cli 0.1.6

Code generator for sqlxplus
sqlxplus-cli-0.1.6 is not a library.

sqlxplus-cli

sqlxplus 的代码生成工具,可以从数据库表结构自动生成 Rust Model 代码,也可以从 Rust Model 代码生成 CREATE TABLE SQL 语句。

安装

从源码安装

cargo install --path cli

从 crates.io 安装(待发布)

cargo install sqlxplus-cli

命令

CLI 工具提供两个主要命令:

  1. generate - 从数据库表结构生成 Rust Model 代码
  2. sql - 从 Rust Model 代码生成 CREATE TABLE SQL 语句

命令:generate

从数据库表结构自动生成 Rust Model 代码,包含完整的字段宏标注(索引、唯一约束、注释等)。

基本用法

# 交互式选择表
sqlxplus-cli generate -d "mysql://user:pass@localhost/dbname"

# 生成所有表
sqlxplus-cli generate -d "mysql://user:pass@localhost/dbname" --all

# 生成指定表
sqlxplus-cli generate -d "mysql://user:pass@localhost/dbname" -t users -t orders

# 指定输出目录
sqlxplus-cli generate -d "mysql://user:pass@localhost/dbname" -o src/models

# 覆盖已存在的文件
sqlxplus-cli generate -d "mysql://user:pass@localhost/dbname" --overwrite

# 预览生成的代码(不写入文件)
sqlxplus-cli generate -d "mysql://user:pass@localhost/dbname" --dry-run

支持的数据库

  • MySQL: mysql://user:pass@localhost/dbname
  • PostgreSQL: postgres://user:pass@localhost/dbname
    • 支持 search_path 参数:postgres://user:pass@localhost/dbname?options=-csearch_path%3Dtest
  • SQLite: sqlite://path/to/database.dbsqlite:path/to/database.db

选项说明

  • -d, --database-url: 数据库连接 URL(必需)
  • -o, --output: 输出目录,默认为 models
  • -t, --tables: 指定要生成的表名(可多次使用)
  • -a, --all: 生成所有表,不进行交互式选择
  • --overwrite: 覆盖已存在的文件
  • --dry-run: 预览模式,不写入文件
  • --serde: 生成 serde 序列化/反序列化 derives(默认启用)
  • --derive-crud: 生成 CRUD derives(默认启用)

生成示例

假设数据库中有以下表:

CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
    username VARCHAR(50) NOT NULL COMMENT '用户名',
    email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱地址',
    is_del TINYINT DEFAULT 0 COMMENT '是否删除',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
) COMMENT '用户表';

运行命令:

sqlxplus-cli generate -d "mysql://user:pass@localhost/dbname" -t users

生成的代码:

#[derive(Debug, Default, sqlx::FromRow, serde::Serialize, serde::Deserialize, sqlxplus::ModelMeta, sqlxplus::CRUD)]
#[model(table = "users", pk = "id", soft_delete = "is_del", table_comment = "用户表")]
pub struct Users {
    /// 主键 | id (bigint) | 非空
    #[column(primary_key, auto_increment, comment = "主键ID")]
    pub id: Option<i64>,
    
    /// username (varchar(50)) | 非空
    #[column(not_null, length = 50, comment = "用户名")]
    pub username: Option<String>,
    
    /// email (varchar(100)) | 非空
    #[column(not_null, unique, index, length = 100, comment = "邮箱地址")]
    pub email: Option<String>,
    
    /// is_del (tinyint) | 非空
    /// 默认值: 0
    #[column(not_null, default = "0", soft_delete, comment = "是否删除")]
    pub is_del: Option<i16>,
    
    /// created_at (timestamp) | 可空
    /// 默认值: CURRENT_TIMESTAMP
    #[column(default = "CURRENT_TIMESTAMP", comment = "创建时间")]
    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
}

生成的字段宏标注

从数据库逆向生成的代码会自动包含以下字段宏标注:

  • primary_key: 主键字段
  • auto_increment: 自增字段
  • not_null: 非空字段
  • default: 默认值
  • length: 字段长度(VARCHAR 等类型)
  • unique: 唯一索引字段
  • index: 普通索引字段
  • soft_delete: 逻辑删除字段(自动检测 is_del, is_deleted, deleted_at 等)
  • comment: 字段注释(从数据库获取)

表注释支持

如果数据库表有注释,会自动生成到 #[model(...)] 属性中:

#[model(table = "users", pk = "id", soft_delete = "is_del", table_comment = "用户表")]

命令:sql

从 Rust Model 代码生成 CREATE TABLE SQL 语句,支持 MySQL、PostgreSQL 和 SQLite。

基本用法

# 生成单个文件的 MySQL SQL
sqlxplus-cli sql -m src/models/user.rs -d mysql -o sql/user_mysql.sql

# 批量生成多个文件的 SQL(可多次使用 -m)
sqlxplus-cli sql -m src/models/user.rs -m src/models/order.rs -d mysql -o sql/all_tables.sql

# 扫描目录下所有 .rs 文件并生成 SQL
sqlxplus-cli sql -D src/models -d mysql -o sql/all_tables.sql

# 组合使用:指定文件 + 扫描目录
sqlxplus-cli sql -m src/models/user.rs -D src/models -d mysql -o sql/all_tables.sql

# 生成 PostgreSQL SQL
sqlxplus-cli sql -m src/models/user.rs -d postgres -o sql/user_postgres.sql

# 生成 SQLite SQL
sqlxplus-cli sql -m src/models/user.rs -d sqlite -o sql/user_sqlite.sql

# 输出到标准输出
sqlxplus-cli sql -m src/models/user.rs -d mysql

选项说明

  • -m, --model: Rust Model 文件路径(可多次使用以指定多个文件)
  • -D, --dir: 扫描目录,自动处理目录下所有 .rs 文件(可选)
  • -d, --database: 数据库类型(mysql, postgres, sqlite),默认为 mysql
  • -o, --output: 输出 SQL 文件路径(可选,不指定则输出到标准输出)

批量处理说明

当批量处理多个文件时:

  • 自动过滤:不符合 model 格式的文件(没有 #[model(...)] 属性的文件)会被自动跳过
  • 结果汇总:处理完成后会显示:
    • ✅ 成功处理的文件列表
    • ⏭️ 忽略的文件列表(没有 model 结构体)
    • ❌ 错误的文件列表(解析错误等)
  • SQL 合并:所有成功处理的文件的 SQL 会合并到一个输出文件中(如果指定了 -o

支持的字段宏标注

SQL 生成器支持以下字段宏标注:

  • primary_key: 生成 PRIMARY KEY 约束
  • auto_increment: 生成 AUTO_INCREMENT(MySQL)或 SERIAL(PostgreSQL)
  • not_null: 生成 NOT NULL 约束
  • default: 生成 DEFAULT 值
  • length: 指定字段长度(如 VARCHAR(255))
  • unique: 生成唯一索引
  • index: 生成普通索引
  • combine_index: 生成联合索引(格式:combine_index = "idx_name:order"
  • soft_delete: 逻辑删除字段(不影响 SQL 生成)
  • comment: 生成字段注释(数据库特定语法)

SQL 生成示例

假设有以下 Rust Model:

#[derive(Debug, Default, sqlx::FromRow, sqlxplus::ModelMeta, sqlxplus::CRUD)]
#[model(table = "user", pk = "id", soft_delete = "is_del", table_comment = "用户表")]
pub struct User {
    #[column(primary_key, auto_increment, comment = "主键ID")]
    pub id: Option<i64>,
    
    #[column(not_null, default = "1", comment = "系统类型")]
    pub system_type: Option<i16>,
    
    #[column(index, length = 255, comment = "用户名")]
    pub username: Option<String>,
    
    #[column(unique, index, length = 255, comment = "邮箱地址")]
    pub email: Option<String>,
    
    #[column(not_null, default = "0", index, soft_delete, comment = "是否删除")]
    pub is_del: Option<i16>,
}

生成的 MySQL SQL:

CREATE TABLE `user` (
    `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `system_type` TINYINT NOT NULL DEFAULT 1 COMMENT '系统类型',
    `username` VARCHAR(255) COMMENT '用户名',
    `email` VARCHAR(255) COMMENT '邮箱地址',
    `is_del` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_user_email` (`email`)
) COMMENT '用户表';

CREATE INDEX `idx_user_username` ON `user` (`username`);
CREATE INDEX `idx_user_is_del` ON `user` (`is_del`);

生成的 PostgreSQL SQL:

CREATE TABLE "user" (
    "id" BIGSERIAL NOT NULL,
    "system_type" SMALLINT NOT NULL DEFAULT 1,
    "username" VARCHAR(255),
    "email" VARCHAR(255),
    "is_del" SMALLINT NOT NULL DEFAULT 0,
    PRIMARY KEY ("id"),
    CONSTRAINT "uk_user_email" UNIQUE ("email")
);

CREATE INDEX "idx_user_username" ON "user" ("username");
CREATE INDEX "idx_user_is_del" ON "user" ("is_del");

COMMENT ON COLUMN "user"."id" IS '主键ID';
COMMENT ON COLUMN "user"."system_type" IS '系统类型';
COMMENT ON COLUMN "user"."username" IS '用户名';
COMMENT ON COLUMN "user"."email" IS '邮箱地址';
COMMENT ON COLUMN "user"."is_del" IS '是否删除';
COMMENT ON TABLE "user" IS '用户表';

特性

代码生成(generate 命令)

  • ✅ 自动检测主键字段
  • ✅ 自动检测逻辑删除字段(is_del, is_deleted, deleted_at 等)
  • ✅ 支持 MySQL、PostgreSQL、SQLite
  • ✅ 支持 PostgreSQL 的 search_path 参数
  • ✅ 交互式表选择
  • ✅ 批量生成多个表
  • ✅ 自动生成 mod.rs 模块文件
  • ✅ 类型映射(SQL 类型 → Rust 类型)
  • ✅ 自动生成字段宏标注(索引、唯一约束、注释等)
  • ✅ 支持表注释和字段注释
  • ✅ 自动检测索引和唯一约束

SQL 生成(sql 命令)

  • ✅ 从 Rust Model 生成 CREATE TABLE SQL
  • ✅ 支持 MySQL、PostgreSQL、SQLite 三种数据库
  • ✅ 生成数据库特定的 SQL 语法
  • ✅ 支持字段注释和表注释
  • ✅ 支持单独索引和联合索引
  • ✅ 支持唯一索引和普通索引
  • ✅ 自动处理数据库类型差异

类型映射

SQL → Rust 类型映射

SQL 类型 Rust 类型
BIGINT, BIGSERIAL i64
INT, INTEGER, SERIAL i32
SMALLINT, TINYINT, SMALLSERIAL i16
VARCHAR, TEXT, CHARACTER VARYING String
DECIMAL, DOUBLE, NUMERIC f64
BOOLEAN, BOOL, BIT bool
DATE chrono::NaiveDate
DATETIME chrono::NaiveDateTime
TIMESTAMP (MySQL) chrono::DateTime<chrono::Utc>
TIMESTAMP WITH TIME ZONE (PostgreSQL) chrono::DateTime<chrono::Utc>
TIMESTAMP WITHOUT TIME ZONE (PostgreSQL) chrono::NaiveDateTime
BLOB, BYTEA Vec<u8>
JSON, JSONB serde_json::Value
UUID uuid::Uuid

类型选择规则

  • 如果字段为 NULLable,生成 Option<T>
  • 如果字段有默认值,生成 Option<T>(因为插入时可以不手动赋值)
  • 如果字段为 NOT NULL 且无默认值,生成 T

使用场景

场景 1:从数据库生成 Model 代码

适用于已有数据库表,需要快速生成对应的 Rust Model 代码:

# 从 PostgreSQL 数据库生成代码
sqlxplus-cli generate \
  -d "postgres://user:pass@localhost/dbname?options=-csearch_path%3Dtest" \
  -t users \
  -o src/models \
  --overwrite

场景 2:从 Model 代码生成 SQL

适用于先定义 Rust Model,然后生成数据库建表 SQL:

# 生成 MySQL 建表 SQL
sqlxplus-cli sql \
  -m src/models/user.rs \
  -d mysql \
  -o migrations/001_create_user.sql

# 批量生成多个表的 SQL
sqlxplus-cli sql \
  -m src/models/user.rs \
  -m src/models/order.rs \
  -d mysql \
  -o migrations/001_create_tables.sql

# 扫描整个目录生成 SQL
sqlxplus-cli sql \
  -D src/models \
  -d mysql \
  -o migrations/001_create_all_tables.sql

场景 3:数据库迁移

结合使用两个命令,实现数据库迁移:

  1. 从旧数据库生成 Model 代码
  2. 修改 Model 代码
  3. 生成新的 SQL 迁移脚本

注意事项

  1. PostgreSQL search_path: 如果使用自定义 schema,需要在连接 URL 中指定:

    postgres://user:pass@localhost/dbname?options=-csearch_path%3Dyour_schema
    
  2. 字段注释:

    • MySQL: 注释直接包含在 CREATE TABLE 语句中
    • PostgreSQL: 使用 COMMENT ON 语句单独添加
    • SQLite: 不支持注释,但会在生成的 SQL 中使用 SQL 注释(--
  3. 索引生成:

    • 唯一索引会同时生成 uniqueindex 属性
    • 联合索引使用 combine_index = "idx_name:order" 格式
  4. 默认值处理:

    • PostgreSQL 的序列(nextval)会被自动识别为 auto_increment
    • 空字符串默认值会正确处理

常见问题

Q: 如何生成包含所有字段宏标注的代码?

A: 使用 generate 命令从数据库生成,会自动包含所有字段宏标注(索引、唯一约束、注释等)。

Q: 生成的代码与手动编写的代码有什么区别?

A: 主要区别在于:

  • 字段类型注释使用数据库实际类型名称(如 PostgreSQL 的 character varying vs MySQL 的 varchar
  • 属性顺序可能略有不同(不影响功能)

Q: 如何支持自定义 schema?

A: 对于 PostgreSQL,在连接 URL 中使用 search_path 参数即可。

License

MIT OR Apache-2.0