4个版本

0.1.4 2023年12月27日
0.1.3 2023年12月27日
0.1.1 2023年12月26日
0.1.0 2023年12月26日

#1781 in 数据库接口

每月 25次下载

MIT 协议

24KB
252

sqlx-pg-seeder

此crate简化了使用Sqlx和Postgres进行数据输入。

0. 更新 [2023-12-27 14:42:59]

  • 0.1.3.version : 已修复版本0.1.2中JSONB和数组字段名称设置为字符串格式的问题。
    从版本0.1.3开始,用户现在可以在'pg-seeder.toml'中指定JSONB和数组字段名称以进行自定义
  • 0.1.4.version : 删除不必要的println,将一些韩文打印语句改为英文

1. 工作流程

此crate主要与API服务器(例如,axum、actix)一起工作。当您将种子文件放置在指定的文件夹(seeder/task)中(所需的JSON格式)时,种子任务成功完成后,文件将从seeder/task移动到seeder/success。

重启服务器后,如果seeder/task中没有JSON文件,crate将跳过该文件夹。因此,如果需要播种数据,将JSON格式的文件放置在该文件夹(seeder/task)中将自动启动种子任务。(种子相关文件夹的位置可以在pg-seeder.toml文件中修改。)

2. 安装和用法

(1) 依赖项(请使用以下选项之一进行安装)

[dependencies]
sqlx-pg-seeder = "0.1.3"
cargo add sqlx-pg-seeder

(2) pg-seeder.toml(种子文件夹位置等配置)

task_folder = "src/seeders/task"
success_folder = "src/seeders/success"
created_at_name = "created_at"
updated_at_name = "updated_at"
jsonb_name = "size"
array_string_name = "thumbnail_src"

task_folder: 放置种子文件的目录。

success_folder: 成功播种后的文件目标位置。

created_at_name and updated_at_name: JSON文件中的字段名称,允许自定义时间戳字段。

  • JSON文件的数量没有限制。即使有多个JSON文件,它们也会在播种完成后一起移动。在此期间,除了以下字符串以外的类型都将直接绑定到由serde_json读取的纯值。由于Postgres中的时间戳类型不支持chrono,因此必须创建并使用单独的trait。因此,根据JSON文件的字段名称,使用分离相应值的机制。作为一种惯例,如果您不使用常用的'created_at(文档创建日期)',则可以为该字段设置单独的名称。

(3) 迁移设置

create extension if not exists "uuid-ossp";

create table if not exists users (
    "id"  serial primary key,
    "uuid" uuid default uuid_generate_v4() not null unique,
    "name" varchar(50) not null,
    "email" varchar(100) not null unique,
    "password" varchar(100) not null,
    "is_admin" boolean not null default false,
    "google_id" varchar(100) unique,
    "naver_id" varchar(100) unique,
    "kakao_id" varchar(100) unique,
    "email_token" text,
    "is_verified" boolean not null default false,
    "pw_email_address" varchar(100),
    "created_at" timestamp not null default now(),
    "updated_at" timestamp not null default now()
);

create table if not exists posts (
    "id"  serial primary key,
    "uuid" uuid default uuid_generate_v4() not null,
    "user_id" uuid not null,
    "title" varchar(100),
    "image_src" text not null,
    "thumbnail_src" text[],
    "description" text not null,
    "brand" varchar(100) not null,
    "category" varchar(100) not null,
    "size"  jsonb not null,
    "price" bigint not null default 0,
    "count_in_stock" bigint not null default 0,
    "rating" double precision not null default 0,
    "num_reviews" bigint not null default 0,
    "sale" bigint not null default 0,
    "free_shipping" bool not null default false,
    "delivery_fee" bigint not null default 0,
    "created_at" timestamp not null default now(),
    "updated_at" timestamp not null default now(),

    constraint fk_user foreign key ("user_id") references "users" ("uuid") on delete cascade
);

[ 注意 ]
使用类型:bigint(整数)、double precision()。Rust默认支持as_i64、as_f64类型转换,因此不能定义小于这些类型。

(4) 服务器设置

(4-1) 如何创建池和迁移

use sqlx::{migrate, FromRow, Pool, Postgres};

#[derive(FromRow)]
pub struct EntityUuid {
  pub uuid: Uuid,
}

#[derive(Clone)]
pub struct DbRepo {
  my_pool: Pool<Postgres>,
}
pub trait DbPoolGetter {
  type Output;
  fn get_pool(&self) -> &Self::Output;
}

impl DbRepo {
  pub async fn init(my_env: &EnvValue) -> Self {
    Self {
      my_pool: get_db_conn(&my_env).await,
    }
  }
}

impl DbPoolGetter for DbRepo {
  type Output = Pool<Postgres>;

  fn get_pool(&self) -> &Self::Output {
    &self.my_pool
  }
}

pub async fn get_db_conn(my_env: &EnvValue) -> Pool<Postgres> {
  println!("Get DB Connect Start!");
  let pg_dialect = &my_env.db_dialect;
  let pg_username = &my_env.db_username;
  let pg_password = &my_env.db_password;
  let pg_host = &my_env.db_host;
  let pg_port = &my_env.db_port;
  let pg_database = &my_env.db_database;

  let pg_url = format!(
    "{pg_dialect}://{pg_username}:{pg_password}@{pg_host}:{pg_port}/{pg_database}"
  );

  let my_pool = sqlx::postgres::PgPool::connect(&pg_url).await.unwrap();

  let migrate = migrate!("./src/migrations").run(&my_pool).await;

  match migrate {
    Ok(()) => println!("sqlx migration success"),
    Err(e) => println!("sqlx migration error : {:?}", e),
  }

  my_pool
}

(4-2) 如何连接种子器

use sqlx_pg_seeder::seeder; 

... 

#[tokio::main]
async fn main() {
  
  ...

  let pool = get_db_conn(&my_env_value).await;

  seeder(&pool).await;

}


关键点在于将连接 PostgreSQL 和 sqlx 的连接池放在种子器中。

这对于在 axum、actix 等框架中使用 sqlx 是必不可少的。这个连接池(预先创建一个连接到数据库的连接池,每当有连接请求时,检索连接并使用它,然后返回,有效地管理和重用数据库连接)是至关重要的。

※ 创建池的一般方法已经概述,但具体细节可能因每个服务器框架而略有不同。这里,我们专注于 axum。

(5) 种子文件

种子文件名与表的名称相对应,并且与 JSON 中的字段名称匹配。默认情况下,初始种子文件位于根据默认设置位于 'src/seeder/task' 文件夹中。

  • users.json
{
  "users": [
    {
      "uuid": "2f806f04-949b-4c28-a091-08a0905ea3ab",
      "name": "Admin User",
      "email": "[email protected]",
      "password": "$2a$10$L/YmXVQY1JGYzJ2/XQULQOgNznOZ21z4.MWmq0TSoskHX25oBXHOa",
      "is_admin": true
    },
    {
      "uuid": "2f806f04-949b-4c28-a091-08a0905ea2ab",
      "name": "IU",
      "email": "[email protected]",
      "password": "$2a$10$L/YmXVQY1JGYzJ2/XQULQOgNznOZ21z4.MWmq0TSoskHX25oBXHOa",
      "is_admin": false
    },
    {
      "uuid": "2f806f04-949b-4c28-a091-08a0905ea3bb",
      "name": "SSaple",
      "email": "[email protected]",
      "password": "$2a$10$L/YmXVQY1JGYzJ2/XQULQOgNznOZ21z4.MWmq0TSoskHX25oBXHOa",
      "is_admin": true
    }]
}
  • posts.json
{
  "posts": [
    {
      "user_id": "2f806f04-949b-4c28-a091-08a0905ea3ab",
      "title": "Set of 4 Business Shirts",
      "image_src": "https://w3s.link/ipfs/bafybeidi7o3o3wiosdqidzrwbiwrgpm3jjltbw22caztuq2xdgtectoj6i/man-shirts-1.jpg",
      "thumbnail_src": [
        "https://w3s.link/ipfs/bafybeidi7o3o3wiosdqidzrwbiwrgpm3jjltbw22caztuq2xdgtectoj6i/man-shirts-1.jpg",
        "https://w3s.link/ipfs/bafybeidujgajt4dby7ws6ii7mg5gkwwjddqoqyvsk4lwisufeupti4fg7i/man-shirts-2.png",
        "https://w3s.link/ipfs/bafybeicbjhyhmokbodeocaxfxahdl4gsxuqqkyeoqsvm46wzqmby7ehcba/footwear-1.png",
        "https://w3s.link/ipfs/bafybeicfvkf34c4rrckfo7h2aipkbgbcnm442bxuot5irbpwoqg7shokfu/footwear-2.png"
      ],
      "description": "A must-have item for your wardrobe! The Polo Boys Oxford Shirt, perfect for matching with both casual and formal looks.",
      "brand": "Polo",
      "category": "Mans",
      "size": { "95": 3, "100": 10, "105": 10, "110": 7 },
      "price": 120000,
      "count_in_stock": 30,
      "rating": 5,
      "num_reviews": 1,
      "sale": 30,
      "free_shipping": true,
      "delivery_fee": 0,
      "created_at": "2022-01-01T00:01:02Z",
      "updated_at": "2022-01-02T00:01:02Z"
    },
    {
      "user_id": "2f806f04-949b-4c28-a091-08a0905ea3ab",
      "title": "Set of 2 Business Shirts",
      "image_src": "https://w3s.link/ipfs/bafybeidujgajt4dby7ws6ii7mg5gkwwjddqoqyvsk4lwisufeupti4fg7i/man-shirts-2.png",
      "thumbnail_src": [
        "https://w3s.link/ipfs/bafybeidujgajt4dby7ws6ii7mg5gkwwjddqoqyvsk4lwisufeupti4fg7i/man-shirts-2.png",
        "https://w3s.link/ipfs/bafybeidi7o3o3wiosdqidzrwbiwrgpm3jjltbw22caztuq2xdgtectoj6i/man-shirts-1.jpg",
        "https://w3s.link/ipfs/bafybeicbjhyhmokbodeocaxfxahdl4gsxuqqkyeoqsvm46wzqmby7ehcba/footwear-1.png",
        "https://w3s.link/ipfs/bafybeicfvkf34c4rrckfo7h2aipkbgbcnm442bxuot5irbpwoqg7shokfu/footwear-2.png"
      ],
      "description": "A must-have item for the transitional season! Get your hands on affordable business shirts!",
      "brand": "Ralph Lauren",
      "category": "Mans",
      "size": { "95": 3, "100": 9, "105": 10, "110": 7 },
      "price": 90000,
      "count_in_stock": 29,
      "rating": 3,
      "num_reviews": 2,
      "sale": 10,
      "free_shipping": false,
      "delivery_fee": 3500,
      "created_at": "2022-01-03T00:01:02Z",
      "updated_at": "2022-01-04T00:01:02Z"
    }]
}

我使用了 web3.storage,它利用 Filecoin IPFS 来存储图片。

3. 其他

sqlx-pg-seeder 支持常用的 Postgres 类型,并且可以适应 sqlx 支持的数据库。

4. 贡献

  • 分支仓库。
  • 创建一个新分支(git checkout -b feature)。
  • 提交您的更改(git commit -am '添加新功能')。
  • 将更改推送到分支(git push origin feature)。
  • 创建一个拉取请求。

5. 许可证:MIT

此包在 [MIT 许可证] 下分发,允许任何人使用、修改、复制和分发软件,前提是提供适当的版权声明。

依赖项

~47MB
~833K SLoC