sqlx-record/entity-update_derive/ReadMe.md

219 lines
5.6 KiB
Markdown

# Update Macro for SQLx
## Overview
This derive macro provides a convenient way to generate update forms and related methods for database entities using SQLx. It's designed to work with MySQL databases and provides flexibility in naming conventions for tables and fields. Additionally, it now supports the use of `id`, `code`, or any custom primary key field through the `primary_key` attribute.
## Features
- Generates an update form struct with optional fields
- Creates methods for generating SQL update statements
- Implements a builder pattern for setting update values
- Provides methods for comparing the update form with both the original model and the database record, returning JSON objects
- Allows custom table names and field names through optional attributes
- Supports specifying custom primary keys with the `primary_key` attribute
- Generates a method to get the table name for use in SQL queries
- Includes an `initial_diff` method to get a JSON representation of all fields in the model
- Supports database transactions for atomic operations
- Optimized for better performance with large structs
## Installation
Add the following to your `Cargo.toml`:
```toml
[dependencies]
entity_update_derive = { path = "path/to/entity_update_derive" }
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "mysql", "json"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
```
## Usage
### Basic Usage with Default Primary Key (`id` or `code`)
```rust
use entity_update_derive::Update;
use sqlx::FromRow;
#[derive(Update, FromRow, Debug)]
struct User {
id: i32,
name: String,
email: Option<String>,
}
```
This will generate a `UserUpdateForm` struct and associated methods, with `id` as the primary key. If your struct uses `code` as the primary key, the macro will automatically detect and use it.
### Specifying a Custom Primary Key
You can specify a custom primary key field using the `primary_key` attribute:
```rust
#[derive(Update, FromRow, Debug)]
struct User {
#[primary_key]
code: String,
name: String,
email: Option<String>,
}
```
### Custom Table Name
You can specify a custom table name using the `table_name` attribute:
```rust
#[derive(Update, FromRow, Debug)]
#[table_name("customers")]
struct User {
id: i32,
name: String,
email: Option<String>,
}
```
### Custom Field Names
You can specify custom field names for the database using the `rename` attribute:
```rust
#[derive(Update, FromRow, Debug)]
struct User {
id: i32,
#[rename("user_name")]
name: String,
#[rename("user_email")]
email: Option<String>,
}
```
### Using the Generated Update Form with Transactions
```rust
use sqlx::mysql::MySqlPool;
use entity_update_derive::Update;
use sqlx::FromRow;
#[derive(Update, FromRow, Debug)]
struct User {
id: i32,
name: String,
email: Option<String>,
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPool::connect("mysql://username:password@localhost/database_name").await?;
let form = User::update_form()
.with_name("new_username".to_string())
.with_email(Some("new_email@example.com".to_string()));
let user_id = 1;
let mut tx = pool.begin().await?;
form.execute_update(&user_id, &mut tx).await?;
let diff = form.transactional_db_diff(&user_id, &mut tx).await?;
println!("Diff: {:?}", diff);
tx.commit().await?;
println!("Update completed successfully");
Ok(())
}
```
## Generated Methods
### `update_form()`
Creates a new instance of the update form.
```rust
let form = User::update_form();
```
### `with_field_name()`
Builder method for each field in the struct.
```rust
let form = User::update_form()
.with_name("New Name")
.with_email(Some("new_email@example.com"));
```
### `update_stmt()`
Generates the SQL SET clause for the update statement.
```rust
let stmt = form.update_stmt();
```
### `bind_values()`
Binds the update values to a SQLx query.
```rust
let query = sqlx::query("UPDATE users SET ...");
let query = form.bind_values(query);
```
### `model_diff()`
Compares the update form with an instance of the original struct and returns a JSON object.
```rust
let diff: serde_json::Value = form.model_diff(&original_user);
```
### `db_diff()`
Compares the update form with the current database record and returns a JSON object.
```rust
let diff: serde_json::Value = form.db_diff(&user_id, &pool).await?;
```
### `table_name()`
Returns the table name as a static string.
```rust
let table_name = UserUpdateForm::table_name();
```
### `initial_diff()`
Returns a JSON object containing all fields of the original model and their current values.
```rust
let user = User {
id: 1,
name: "John Doe".to_string(),
email: Some("john@example.com".to_string()),
};
let initial_diff: serde_json::Value = user.initial_diff();
```
## Notes
- This macro now supports custom primary key fields using the `primary_key` attribute. If not specified, it defaults to checking for an `id` or `code` field.
- The macro assumes you're using MySQL. Modifications may be needed for other database types.
- Error handling is minimal in these examples. In a production environment, you should implement proper error handling and logging.
- The `model_diff()`, `db_diff()`, and `initial_diff()` methods return `serde_json::Value` objects, which are easy to work with when dealing with JSON data.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is licensed under the Nandie Software Proprietary License. See the LICENSE file in the project root for the full license text.