diff --git a/cli/src/generator/models/actions.rs b/cli/src/generator/models/actions.rs index c5c62a23..4b376bb8 100644 --- a/cli/src/generator/models/actions.rs +++ b/cli/src/generator/models/actions.rs @@ -86,7 +86,7 @@ pub fn create_many_fn(model: &dml::Model) -> Option { .unzip(); Some(quote! { - pub fn create_many(self, data: Vec<(#(#types,)* Vec)>) -> CreateMany<'a> { + pub fn create_many(self, data: Vec<(#(#types,)* Vec)>) -> CreateMany<'a> { let data = data.into_iter().map(|(#(#names,)* mut _params)| { _params.extend([ #(#names::set(#names)),* @@ -213,7 +213,7 @@ pub fn struct_definition(model: &dml::Model, args: &GenerateArgs) -> TokenStream ) } - pub fn update_many(self, _where: Vec, _params: Vec) -> UpdateMany<'a> { + pub fn update_many(self, _where: Vec, _params: Vec) -> UpdateMany<'a> { UpdateMany::new( self.client, _where, diff --git a/cli/src/generator/models/create.rs b/cli/src/generator/models/create.rs index 91229ead..188a36c1 100644 --- a/cli/src/generator/models/create.rs +++ b/cli/src/generator/models/create.rs @@ -27,8 +27,8 @@ fn create_unchecked(model: &dml::Model) -> Option { .unzip(); Some(quote! { - pub fn create_unchecked(#(#names: #types,)* _params: Vec) - -> (#(#types,)* Vec) { + pub fn create_unchecked(#(#names: #types,)* _params: Vec) + -> (#(#types,)* Vec) { (#(#names,)* _params) } }) diff --git a/cli/src/generator/models/data.rs b/cli/src/generator/models/data.rs index 4efaaab2..74bcedfe 100644 --- a/cli/src/generator/models/data.rs +++ b/cli/src/generator/models/data.rs @@ -41,7 +41,7 @@ enum Field<'a> { Composite(CompositeField<'a>), } -pub fn struct_definition(model: &dml::Model, module_path: &TokenStream) -> TokenStream { +pub fn struct_definition(model: &dml::Model) -> TokenStream { let pcr = quote!(::prisma_client_rust); let fields = model diff --git a/cli/src/generator/models/mod.rs b/cli/src/generator/models/mod.rs index 80cd27a0..3eb4b68d 100644 --- a/cli/src/generator/models/mod.rs +++ b/cli/src/generator/models/mod.rs @@ -5,7 +5,7 @@ mod field; mod include_select; mod order_by; mod pagination; -mod partial; +mod partial_unchecked; mod set_params; mod types; mod where_params; @@ -275,7 +275,7 @@ pub fn modules(args: &GenerateArgs, module_path: &TokenStream) -> Vec Vec(model: &'a dml::Model, module_path: &TokenStream) -> TokenStream { let model_name_snake = snake_ident(&model.name); let model_name_snake_raw = snake_ident_raw(&model.name); - let macro_name = format_ident!("_partial_{model_name_snake_raw}"); + let macro_name = format_ident!("_partial_unchecked_{model_name_snake_raw}"); let model_module = quote!(#module_path::#model_name_snake); @@ -33,7 +33,7 @@ pub fn model_macro<'a>(model: &'a dml::Model, module_path: &TokenStream) -> Toke ($struct_name:ident { $($scalar_field:ident)+ }) => { - ::prisma_client_rust::macros::partial! { + ::prisma_client_rust::macros::partial_unchecked! { #model_module struct $struct_name { #(#struct_fields),* @@ -43,6 +43,6 @@ pub fn model_macro<'a>(model: &'a dml::Model, module_path: &TokenStream) -> Toke }; } - pub use #macro_name as partial; + pub use #macro_name as partial_unchecked; } } diff --git a/docs/pages/extra/_meta.json b/docs/pages/extra/_meta.json index e0a0ddad..0e5f4d9b 100644 --- a/docs/pages/extra/_meta.json +++ b/docs/pages/extra/_meta.json @@ -3,10 +3,10 @@ "batching": "Batching Queries", "transactions": "Transactions", "composite-types": "Composite Types", + "partial-types": "Partial Types", "mocking": "Mocking Queries", "error-handling": "Error Handling", "migrations": "Migrations", - "partial-types": "Partial Types", "rspc": "rspc Integration", "traits": "Query Traits" } diff --git a/docs/pages/extra/composite-types.md b/docs/pages/extra/composite-types.md index 9a2a9f3c..f7173a85 100644 --- a/docs/pages/extra/composite-types.md +++ b/docs/pages/extra/composite-types.md @@ -1,5 +1,7 @@ # Composite Types +_Available since v0.6.7_ + When using MongoDB you will likely need to use [`embedded documents`](https://www.mongodb.com/docs/manual/core/data-model-design/#std-label-data-modeling-embedding), which Prisma calls 'Composite Types'. Prisma Client Rust will generate field & type modules whenever you use composite types, diff --git a/docs/pages/extra/partial-types.md b/docs/pages/extra/partial-types.md index 7ac365fe..ec09eb6e 100644 --- a/docs/pages/extra/partial-types.md +++ b/docs/pages/extra/partial-types.md @@ -1,9 +1,9 @@ -# Partial Types +# Partial Types _Available since v0.6.7_ -The `partial!` macro can be found in all model modules, -and allows structs to be defined that have a `to_params` function which converts them for use inside `update` and `upsert` queries. +The `partial_unchecked!` macro can be found in all model modules, +and allows structs to be defined that have a `to_params` function which converts them for use inside `update_unchecked`. Each field of the generated structs has the same type as the equivalent field in the module's `Data` struct, just wrapped inside `Option`. @@ -12,9 +12,14 @@ This can be useful for thing like web APIs built with [`rspc`](https://www.rspc.dev/), where receiving updates is more ergonomic as structs rather than a list of changes. -Currently `partial!` only supports scalar fields. -Support for relations will be considered once [nested writes](https://github.com/Brendonovich/prisma-client-rust/issues/44) -are implemented. +A more general `partial!` does not yet exist, +as supporting relations is not possible until [nested writes](https://github.com/Brendonovich/prisma-client-rust/issues/44) +are supported. + +## Setup + +Using partial macros requires the same setup as [Select & Include](/reading-data/select-include#setup), +as `module_path` must be provided. ## Example @@ -31,7 +36,7 @@ model Post { An updater function can be written like so: ```rust -post::partial!(PostUpdateData { +post::partial_unchecked!(PostUpdateData { title content }) @@ -42,13 +47,13 @@ pub async fn update_post( data: PostUpdateData ) { db.post() - .update(post::id::equals(id), data.to_params()) + .update_unchecked(post::id::equals(id), data.to_params()) .exec() .await; } ``` -The above use of `partial!` generates the following: +The above use of `partial_unchecked!` generates something like the following: ```rust pub struct PostUpdateData { @@ -57,7 +62,7 @@ pub struct PostUpdateData { } impl PostUpdateData { - pub fn to_params(self) -> Vec { + pub fn to_params(self) -> Vec { [ self.title.map(post::title::set), self.content.map(post::content::set) @@ -65,8 +70,3 @@ impl PostUpdateData { } } ``` - - -## Specta - - diff --git a/docs/pages/extra/raw.md b/docs/pages/extra/raw.md index b694d117..d13b090f 100644 --- a/docs/pages/extra/raw.md +++ b/docs/pages/extra/raw.md @@ -77,6 +77,8 @@ assert_eq!(count, 1); ## MongoDB +_Available since v0.6.7_ + When using MongDB, the client exposes multiple functions for performing raw queries that use [`serde_json::Value`](https://docs.rs/serde_json/latest/serde_json/value/enum.Value.html) as arguments. diff --git a/docs/pages/index.md b/docs/pages/index.md index 3ea55a11..8de4b622 100644 --- a/docs/pages/index.md +++ b/docs/pages/index.md @@ -6,6 +6,15 @@ as a lot of concepts are shared from them and will not be explained here. Prisma Client Rust is not an official Prisma product, but has been [generously supported](https://twitter.com/prisma/status/1554855900124438529) as part of their FOSS Fund. +## Examples + +- [Actix](https://github.com/Brendonovich/prisma-client-rust/tree/main/examples/actix) +- [Axum](https://github.com/Brendonovich/prisma-client-rust/tree/main/examples/axum-rest) +- [Axum + `async-graphql`](https://github.com/Brendonovich/prisma-client-rust/tree/main/examples/axum-graphql) +- [Rocket](https://github.com/Brendonovich/prisma-client-rust/tree/main/examples/rocket) +- [rspc](https://github.com/Brendonovich/prisma-client-rust/tree/main/examples/rspc) +- [Tauri](https://github.com/Brendonovich/prisma-client-rust/tree/main/examples/tauri) + ## In The Wild - [Spacedrive](https://spacedrive.com) - Prisma Client Rust wouldn't exist without Spacedrive (my employer), diff --git a/docs/pages/writing-data/create.md b/docs/pages/writing-data/create.mdx similarity index 81% rename from docs/pages/writing-data/create.md rename to docs/pages/writing-data/create.mdx index bbeac651..3fdd8718 100644 --- a/docs/pages/writing-data/create.md +++ b/docs/pages/writing-data/create.mdx @@ -94,19 +94,45 @@ let comment: comment::Data = client Connecting records like this is equivalent to directly setting the values of the relation's foreign keys, eg. setting `post_id` from the above example with `comment::post_id::set()`. + +## Create Unchecked + +_Available since v0.6.7_ + +`create_unchecked` is similar to `create` but only allows setting scalar fields using `UncheckedSetParam`. +`unchecked` is a Prisma term describing inputs that only accept a model's scalar fields. + +```rust +use prisma::{comment, post}; + +let comment: comment::Data = client + .comment() + .create( + "content".to_string(), + // requires specifying field for postID, + // rather than connecting a relation + 0, + vec![] + ) + .exec() + .await?; +``` + ## Create Many `create_many` can be used to create many records of a single model type. -It accepts a `Vec` of tuples with a similar shape as the arguments to `create`, -except only scalar fields can be provided. -Connecting relations using relation field operations is not possible. +It accepts a `Vec` of tuples with the same shape as `create_unchecked`, +so only scalar fields can be set. + +import { Callout } from "nextra-theme-docs"; + + + SQLite support for `create_many` is **UNSTABLE**, + but can be enabled by adding the `sqlite-create-many` feature to `prisma-client-rust` and `prisma-client-rust-cli` in your `Cargo.toml` files. + To assist in constructing tuples of the right shape, each model module contains a `create_unchecked` function that accepts a model's scalar fields and returns the correct tuple. -`unchecked` is a Prisma term, -describing inputs that only accept a model's scalar fields. - -SQLite support for `create_many` is **UNSTABLE**, but can be enabled by adding the `sqlite-create-many` feature to `prisma-client-rust` and `prisma-client-rust-cli` in your `Cargo.toml` files. The following example iterates an array of titles, turns it into tuples and creates multiple posts. diff --git a/docs/pages/writing-data/update.md b/docs/pages/writing-data/update.md index 361bd424..2d3b37a8 100644 --- a/docs/pages/writing-data/update.md +++ b/docs/pages/writing-data/update.md @@ -49,6 +49,25 @@ let updated_post: post::Data = client .await?; ``` +## Update Unchecked + +_Available since v0.6.7_ + +`update_unchecked` is similar to `update` but only allows setting scalar fields using `UncheckedSetParam`. + +```rust +use prisma::{comment, post}; + +let comment: comment::Data = client + .comment() + .update( + comment::id::equals("some comment id".to_string()), + vec![comment::post_id::set("some post id".to_string())] + ) + .exec() + .await?; +``` + ## Update Many `update_many` accepts a `Vec` of filters (not just unique filters), and a `Vec` of updates to apply to all records found. diff --git a/integration-tests/tests/partial.rs b/integration-tests/tests/partial.rs index 488b0a3c..a025fc13 100644 --- a/integration-tests/tests/partial.rs +++ b/integration-tests/tests/partial.rs @@ -1,6 +1,6 @@ use crate::{db::*, utils::*}; -user::partial!(UserPartialType { +user::partial_unchecked!(UserPartialType { name email }); @@ -22,7 +22,7 @@ async fn scalars() -> TestResult { let updated_user = client .user() - .update(user::id::equals(user.id), updates.to_params()) + .update_unchecked(user::id::equals(user.id), updates.to_params()) .exec() .await?; diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 69afc460..a579a171 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,4 +1,4 @@ -mod partial; +mod partial_unchecked; #[proc_macro] pub fn to_pascal_case(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -7,6 +7,6 @@ pub fn to_pascal_case(input: proc_macro::TokenStream) -> proc_macro::TokenStream proc_macro::TokenTree::Literal(proc_macro::Literal::string(&converted)).into() } #[proc_macro] -pub fn partial(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - partial::proc_macro(input) +pub fn partial_unchecked(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + partial_unchecked::proc_macro(input) } diff --git a/macros/src/partial.rs b/macros/src/partial_unchecked.rs similarity index 88% rename from macros/src/partial.rs rename to macros/src/partial_unchecked.rs index 48836fbd..404de46a 100644 --- a/macros/src/partial.rs +++ b/macros/src/partial_unchecked.rs @@ -4,13 +4,13 @@ use syn::{ bracketed, parse::Parse, parse_macro_input, punctuated::Punctuated, ItemStruct, Path, Token, }; -struct PartialInput { +struct PartialUncheckedInput { model_module: Path, data: ItemStruct, selection: Punctuated, } -impl Parse for PartialInput { +impl Parse for PartialUncheckedInput { fn parse(input: syn::parse::ParseStream) -> syn::Result { Ok(Self { model_module: input.parse()?, @@ -25,11 +25,11 @@ impl Parse for PartialInput { } pub fn proc_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let PartialInput { + let PartialUncheckedInput { model_module, data, selection, - } = parse_macro_input!(input as PartialInput); + } = parse_macro_input!(input as PartialUncheckedInput); let fields = data .fields @@ -69,7 +69,7 @@ pub fn proc_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } impl #ident { - pub fn to_params(self) -> Vec<#model_module::SetParam> { + pub fn to_params(self) -> Vec<#model_module::UncheckedSetParam> { [ #(self.#selection.map(#model_module::#selection::set)),* ].into_iter().flatten().collect() diff --git a/src/queries/create_many.rs b/src/queries/create_many.rs index f223d777..494ffb53 100644 --- a/src/queries/create_many.rs +++ b/src/queries/create_many.rs @@ -8,15 +8,12 @@ use crate::{ pub struct CreateMany<'a, Actions: ModelTypes> { client: &'a PrismaClientInternals, - pub set_params: Vec>, + pub set_params: Vec>, pub skip_duplicates: bool, } impl<'a, Actions: ModelTypes> CreateMany<'a, Actions> { - pub fn new( - client: &'a PrismaClientInternals, - set_params: Vec>, - ) -> Self { + pub fn new(client: &'a PrismaClientInternals, set_params: Vec>) -> Self { Self { client, set_params, @@ -31,7 +28,7 @@ impl<'a, Actions: ModelTypes> CreateMany<'a, Actions> { } fn to_selection( - set_params: Vec>, + set_params: Vec>, _skip_duplicates: bool, nested_selections: impl IntoIterator, ) -> Selection { diff --git a/src/queries/update_many.rs b/src/queries/update_many.rs index dab24ffd..6d384ba7 100644 --- a/src/queries/update_many.rs +++ b/src/queries/update_many.rs @@ -3,20 +3,20 @@ use query_core::Operation; use crate::{ merge_fields, BatchResult, ModelOperation, ModelQuery, ModelTypes, ModelWriteOperation, - PrismaClientInternals, Query, QueryConvert, UncheckedSetQuery, WhereInput, WhereQuery, + PrismaClientInternals, Query, QueryConvert, SetQuery, WhereInput, WhereQuery, }; pub struct UpdateMany<'a, Actions: ModelTypes> { client: &'a PrismaClientInternals, pub where_params: Vec, - pub set_params: Vec, + pub set_params: Vec, } impl<'a, Actions: ModelTypes> UpdateMany<'a, Actions> { pub fn new( client: &'a PrismaClientInternals, where_params: Vec, - set_params: Vec, + set_params: Vec, ) -> Self { Self { client, @@ -90,8 +90,8 @@ impl<'a, Actions: ModelTypes> WhereQuery<'a> for UpdateMany<'a, Actions> { } } -impl<'a, Actions: ModelTypes> UncheckedSetQuery<'a> for UpdateMany<'a, Actions> { - fn add_unchecked_set(&mut self, param: Actions::UncheckedSet) { +impl<'a, Actions: ModelTypes> SetQuery<'a> for UpdateMany<'a, Actions> { + fn add_set(&mut self, param: Actions::Set) { self.set_params.push(param); } }