Rust PostgreSQL扩展开发库pgrx-sql-entity-graph的使用,为PostgreSQL提供Rust语言绑定与实体映射功能

pgrx-sql-entity-graph

用于pgrx的SQL实体图生成。这个crate被各种pgrx crate内部使用。

元数据

  • 版本: 0.16.0
  • 发布时间: 15天前
  • 版本: 2021 edition
  • 许可证: MIT
  • 大小: 74.1 KiB

安装

在项目目录中运行以下Cargo命令:

cargo add pgrx-sql-entity-graph

或者在Cargo.toml中添加以下行:

pgrx-sql-entity-graph = "0.16.0"

所有者

  • Eric Ridge
  • Jubilee
  • PgCentral Foundation, Inc.

完整示例代码

以下是一个使用pgrx-sql-entity-graph开发PostgreSQL扩展的完整示例:

use pgrx::prelude::*;
use pgrx_sql_entity_graph::PostgresType;

// 定义一个PostgreSQL函数
#[pg_extern]
fn hello_pgrx(name: String) -> String {
    format!("Hello, {}!", name)
}

// 定义一个复合类型
#[derive(PostgresType)]
struct Person {
    name: String,
    age: i32,
}

// 定义一个返回复合类型的函数
#[pg_extern]
fn create_person(name: String, age: i32) -> Person {
    Person { name, age }
}

// 定义一个返回表的函数
#[pg_extern]
fn generate_series(start: i32, end: i32, step: i32) -> 
    TableIterator<'static, (name!(value, i32),)> 
{
    TableIterator::new((start..=end).step_by(step as usize).map(|i| (i,)))
}

// 定义扩展入口点
#[cfg(any(test, feature = "pg_test"))]
#[pg_schema]
mod tests {
    use pgrx::prelude::*;

    #[pg_test]
    fn test_hello_pgrx() {
        assert_eq!("Hello, pgrx!", crate::hello_pgrx("pgrx".into()));
    }
}

#[allow(dead_code)]
#[cfg(not(target_os = "windows"))]
#[cfg(any(test, feature = "pg_test"))]
#[pg_schema]
mod pg_test {
    pub fn setup(_options: Vec<&str>) {
        // 执行一次性测试设置
    }

    pub fn postgresql_conf_options() -> Vec<&'static str> {
        // 返回要在测试期间设置的Postgres配置选项
        vec![]
    }
}

这个示例展示了:

  1. 定义基本的PostgreSQL函数
  2. 定义和使用复合类型
  3. 定义返回表的函数
  4. 包含测试模块
  5. 支持测试配置

要使用这个扩展,你需要配置Cargo.toml添加pgrx和pgrx-sql-entity-graph作为依赖项。


1 回复

pgrx-sql-entity-graph: Rust PostgreSQL扩展开发库

概述

pgrx-sql-entity-graph 是一个用于开发 PostgreSQL 扩展的 Rust 库,它为 PostgreSQL 提供了 Rust 语言绑定和实体映射功能。这个库是 pgrx 生态系统的一部分,旨在简化使用 Rust 编写 PostgreSQL 扩展的过程。

主要功能

  1. 提供 Rust 与 PostgreSQL 之间的类型映射
  2. 简化实体关系映射 (ORM-like 功能)
  3. 支持 PostgreSQL 扩展开发
  4. 自动生成 SQL 定义

安装与配置

首先,确保你已经安装了 pgrx 工具链:

cargo install --locked cargo-pgrx
cargo pgrx init

然后在你的 Cargo.toml 中添加依赖:

[dependencies]
pgrx = "0.7"
pgrx-sql-entity-graph = "0.7"

基本使用方法

1. 定义实体

use pgrx::prelude::*;
use pgrx_sql_entity_graph::PostgresType;

#[derive(PostgresType)]
pub struct Person {
    name: String,
    age: i32,
    email: Option<String>,
}

2. 实现 PostgreSQL 函数

use pgrx::prelude::*;

#[pg_extern]
fn create_person(name: String, age: i32) -> Person {
    Person {
        name,
        age,
        email: None,
    }
}

#[pg_extern]
fn get_person_age(person: Person) -> i32 {
    person.age
}

3. 使用实体关系映射

use pgrx::prelude::*;
use pgrx_sql_entity_graph::{PostgresType, PostgresEnum};

#[derive(PostgresEnum)]
pub enum Gender {
    Male,
    Female,
    Other,
}

#[derive(PostgresType)]
pub struct Employee {
    person: Person,
    gender: Gender,
    salary: f64,
}

高级功能示例

自定义类型转换

use pgrx::prelude::*;
use pgrx_sql_entity_graph::PostgresType;

#[derive(PostgresType)]
#[pgvarlena_inoutfuncs]
pub struct ComplexNumber {
    real: f64,
    imaginary: f64,
}

impl ComplexNumber {
    #[pg_extern]
    pub fn new(real: f64, imaginary: f64) -> Self {
        Self { real, imaginary }
    }

    #[pg_extern]
    pub fn add(&self, other: &ComplexNumber) -> ComplexNumber {
        ComplexNumber {
            real: self.real + other.real,
            imaginary: self.imaginary + other.imaginary,
        }
    }
}

生成表定义

use pgrx::prelude::*;
use pgrx_sql_entity_graph::{PostgresType, PgCatalog};

#[derive(PostgresType, PgCatalog)]
pub struct Product {
    id: i64,
    name: String,
    price: f64,
    in_stock: bool,
}

#[pg_extern]
fn get_expensive_products(price_threshold: f64) -> Vec<Product> {
    // 这里实现从数据库获取高价产品的逻辑
    vec![]
}

完整示例代码

以下是一个完整的 PostgreSQL 扩展示例,实现了一个简单的用户管理系统:

use pgrx::prelude::*;
use pgrx_sql_entity_graph::{PostgresType, PostgresEnum, PgCatalog};
use serde::{Serialize, Deserialize};

// 定义用户角色枚举
#[derive(PostgresEnum, Serialize, Deserialize)]
pub enum UserRole {
    Guest,
    User,
    Admin,
}

// 定义用户实体
#[derive(PostgresType, PgCatalog, Serialize, Deserialize)]
pub struct User {
    id: i64,                     // 用户ID
    username: String,            // 用户名
    password_hash: String,       // 密码哈希
    email: Option<String>,       // 可选邮箱
    role: UserRole,              // 用户角色
    created_at: Timestamp,       // 创建时间
    last_login: Option<Timestamp>, // 最后登录时间
}

// 用户管理功能实现
#[pg_extern]
fn create_user(
    username: String,
    password: String,
    email: Option<String>,
    role: UserRole
) -> User {
    // 在实际应用中应该对密码进行哈希处理
    let password_hash = format!("hashed_{}", password); 
    
    User {
        id: nextval("user_id_seq"),  // 使用序列生成ID
        username,
        password_hash,
        email,
        role,
        created_at: Timestamp::now(),
        last_login: None,
    }
}

#[pg_extern]
fn update_user_role(user_id: i64, new_role: UserRole) -> Result<User, String> {
    // 实际应用中这里会查询并更新数据库中的用户
    // 这里简化实现返回一个模拟用户
    Ok(User {
        id: user_id,
        username: "updated_user".into(),
        password_hash: "hashed_password".into(),
        email: Some("updated@example.com".into()),
        role: new_role,
        created_at: Timestamp::now(),
        last_login: Some(Timestamp::now()),
    })
}

#[pg_extern]
fn get_users_by_role(role: UserRole) -> Vec<User> {
    // 实际应用中这里会查询数据库
    // 这里返回模拟数据
    vec![
        User {
            id: 1,
            username: "admin_user".into(),
            password_hash: "hashed_admin".into(),
            email: Some("admin@example.com".into()),
            role: UserRole::Admin,
            created_at: Timestamp::now(),
            last_login: Some(Timestamp::now()),
        },
        User {
            id: 2,
            username: "regular_user".into(),
            password_hash: "hashed_regular".into(),
            email: Some("user@example.com".into()),
            role: UserRole::User,
            created_at: Timestamp::now(),
            last_login: Some(Timestamp::now()),
        }
    ]
    .into_iter()
    .filter(|user| user.role == role)
    .collect()
}

// 扩展入口点
#[pg_module]
pub mod user_management {
    pub fn setup() {
        // 模块初始化代码
    }
}

注意事项

  1. 确保你的 Rust 类型与 PostgreSQL 类型兼容
  2. 复杂类型需要实现适当的转换 trait
  3. 在开发过程中使用 cargo pgrx run 测试你的扩展
  4. 生产环境部署前进行充分的测试

pgrx-sql-entity-graph 为 Rust 开发者提供了强大的工具来构建高性能的 PostgreSQL 扩展,同时保持类型安全和代码可维护性。

回到顶部