读取数据
选择与包含

选择与包含

使用 with/fetch 来获取关联是可以的,但在类型安全性方面还有待改进。选择与包含查询构建器函数和宏可以帮助解决这个问题,为每个您选择获取的字段和关联提供精确的类型。

Select 还提供了仅获取特定字段的功能,而 include 将获取所有标量字段和任何指定的关联。

示例使用以下模式

model Post {
    id        String   @id @default(cuid())
    title     String
 
    comments Comment[]
}
 
model Comment {
    id        String   @id @default(cuid())
    content   String
 
    post   Post   @relation(fields: [postID], references: [id])
    postID String
}

设置

select!include! 依赖于递归并在内部相互调用,因此它们必须知道生成的客户端的模块路径。默认情况下,这是 crate::prisma,它假设您的客户端生成到一个名为 prisma.rs 的文件,并且位于它所在的板条箱的根目录。如果您已将客户端配置为具有不同的名称或位于其他位置,则需要通过 module_path 生成器选项提供此位置。

module_path 是相对于 crate 的 Rust 路径,指向您生成的客户端。

generator client {
    provider      = "cargo prisma"
    output        = "./src/generated/db.rs"
    // `select` macros will now point to `crate::generated::db`
    // instead of `crate::prisma`
    module_path   = "generated::db"
}

基础

select!include! 在语法上非常相似,它们唯一的区别在于它们做什么以及不做什么。每个模型模块都包含 select!include! 宏,其结果可以提供给它们各自的查询构建器函数。

要获取的字段可以指定为 {} 内部的空格分隔列表

post::select!({
    id    // select can pick individual fields
    title
})
 
// Above will generate
struct Data {
    id: String,
    title: String,
}
post::include!({
    comments // include can only pick relations
})
 
// Above will generate
struct Data {
    id: String,
    title: String,
    comments: Vec<comment::Data>
}

嵌套选择

selectinclude 也可以在获取关联时应用,实际上可以应用到任何深度。只需添加一个 :,指定您是否要在关联上选择或包含,并添加您的选择

// Nested include inside select
post::select!({
    comments: include {
        post
    }
})
 
// Above will generate
struct Data {
    comments: comments::Data // refers to below module
}
 
// Module + data struct generated for nested selection
mod comments {
    pub struct Data {
        post: post::Data
    }
}
// Nested select inside include
post::include!({
    comments: select {
        content
    }
})
 
// Above will generate
struct Data {
    id: String,
    title: String,
    comments: comments::Data // refers to below module
}
 
// Module + data struct generated for nested selection
mod comments {
    pub struct Data {
        content: String
    }
}

多关系选项

在获取多关系时,获取语句可以充当对 model::field::fetch 的等效调用,允许进行过滤、分页和排序。这在 select!include! 中都有效。

post::select!({
    // Equivalent to post::comments::fetch(..) ..
    comments(vec![comment::content::contains("prisma".to_string())])
        .skip(5)
        .take(10): select { // You can add on nested selections too!
        id
        content
    }
})

在查询中使用

只需将 select!include! 的结果传递给等效的查询构建器函数

// Type is anonymous and does not exist outside of the call to `include`
let posts: Vec<_> = client
    .post()
    .find_many(vec![])
    .include(post::include!({
        comments: select {
            id
        }
    }))
    .exec()
    .await?;
 
// Generated type is equivalent to
struct Data {
    id: String,
    title: String,
    comments: comments::Data
}
 
mod comments {
    pub struct Data {
        id: String
    }
}

在查询之外使用类型

在某些情况下,访问 select!include! 生成的类型在对查询构建器函数的调用之外可能很有用,例如,如果您想从函数返回查询的结果。

这可以通过在根选择之前添加名称来完成。这将导致生成一个具有该名称的模块,并且该模块将包含一个 Data 结构体以及一个 includeselect 函数,具体取决于您使用哪个宏。

post::select!(post_only_title {
    title
})
 
async fn do_query() -> Vec<post_only_title::Data> {
    client
        .post()
        .find_many(vec![])
        .select(post_only_title::select())
        .exec()
        .await
        .unwrap()
}
 
// Generated type is equivalent to
pub mod post_only_title {
    pub struct Data {
        title: String
    }
 
    pub fn select() // return type is an internal detail
}

传递参数

在内联执行选择时,外部值可以很好地用作参数,因为它们可以从宏外部捕获。当选择在查询构建器函数外部声明时,无法捕获此上下文。这就是为什么selectinclude 函数不仅仅是结构体,它们可以使用以下语法传递在宏中定义的参数

 
post::include!((filters: Vec<comment::WhereParam>, skip: i64, take: i64) => post_with_comments {
    comments(filters).skip(skip).take(take)
})
 
async fn do_query() -> Vec<post_only_title::Data> {
    let filters = vec![comment::content::contains("prisma".to_string())];
    let skip = 5;
    let take = 5;
 
    client
        .post()
        .find_many(vec![])
        .select(post_only_title::select(filters, skip, take))
        .exec()
        .await
        .unwrap()
}
 
// Generated type is equivalent to
pub mod post_with_comments {
    pub struct Data {
        id: String,
        title: String,
        comments: Vec<comment::Data>
    }
 
    pub fn select(filters: Vec<comment::WhereParam>, skip: i64, take: i64) // return type is an internal detail
}