Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 110 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,20 @@

A utility to generate database structs and querying code from diesel schema files. Primarily built for [create-rust-app](https://github.com/Wulf/create-rust-app).

**Why?**

Currently, it's more advantageous to generate code over deriving code with macros because intellisense and autocompletion isn't quite there when it comes to macro expansion.

**Migrating from v0 to v1? See migration notes below.**

## Features

- Supports `diesel-async` (enable `async` feature flag)
- Generates structs based on your `schema.rs` file (see the `test/simple_table` folder for sample output)
- Optionally generates CRUD functions and helper methods
- Use as a binary or library (read more below)
- Many options (see `GenerationConfig` in `lib.rs`) -- you have the ability to customize generated code for specific tables; or entirely ignore a specific table!

## Demo

Given the following schema:
Expand All @@ -30,20 +42,47 @@ cargo dsync -i schema.rs -o models
Now we have everything we need!

```rust
use models::todos;

async fn demo(db: Connection) {
let created_todo = todos::create(&mut db, todos::CreateTodo {
/*
CRUD examples
*/
let created_todo = Todo::create(db, CreateTodo {
text: "Create a demo",
completed: false,
}).await?;

let todos_list = todos::paginate(&mut db, 1, 10).await?;

let updated_todo = todos::update(&mut db, created_todo.id, UpdateTodo {
})?;

let todos_list = Todo::paginate(db, 1, 10)?;

let read_todo = Todo::read(db, created_todo.id)?;

let updated_todo = Todo::update(db, created_todo.id, UpdateTodo {
text: created_todo.text,
completed: true,
}).await?;
})?;

let deleted_todo = Todo::delete(db, created_todo.id)?;

/*
Use the "Filter" helper
--> Works well with intellisense! <--
--> Easily create reusable/portable queries! <--

(Support for date/time and other types coming soon)
*/

// example: fetch incomplete todos
let query = Todo::filter(TodoFilter {
completed: Some(false),
..Default::default()
});
let items: Vec<Todo> = query.load(db)?;

// example: delete completed todos
let query = Todo::filter(TodoFilter {
completed: Some(true),
..Default::default()
})
diesel::delete(query).execute(db)?;
}
```

Expand All @@ -59,66 +98,76 @@ For a complete example, see [`test/simple_table/schema.rs`](test/simple_table/sc

2. Create a new binary in your project which uses the crate (for example, `bin/dsync.rs`)

```rust
use std::{collections::HashMap, path::PathBuf};
use dsync::{GenerationConfig, TableOptions};
pub fn main() {
let dir = env!("CARGO_MANIFEST_DIR");
dsync::generate_files(
PathBuf::from_iter([dir, "src/schema.rs"]),
PathBuf::from_iter([dir, "src/models"]),
GenerationConfig { /* ... your generation options ... */ }
);
}
```
```rust
use std::{collections::HashMap, path::PathBuf};
use dsync::{GenerationConfig, TableOptions};

pub fn main() {
let dir = env!("CARGO_MANIFEST_DIR");

dsync::generate_files(
PathBuf::from_iter([dir, "src/schema.rs"]),
PathBuf::from_iter([dir, "src/models"]),
GenerationConfig { /* ... your generation options ... */ }
);
}
```

3. Create a `Cargo.toml` binary entry:

```toml
[[bin]]
name = "dsync"
path = "bin/dsync.rs"
```
```toml
[[bin]]
name = "dsync"
path = "bin/dsync.rs"
```

4. Execute!

```sh
cargo run --bin dsync
```
```sh
cargo run --bin dsync
```

**Protip**: to use `cargo dsync`, create an alias in `.cargo/config`:
```toml
[alias]
dsync="run --bin dsync"
```
**Protip**: to use `cargo dsync`, create an alias in `.cargo/config`:

```toml
[alias]
dsync="run --bin dsync"
```

### Pre-built binary

Setting up a custom binary allows you to completely customize the generation; however, if complete customization isn't necessary, you can install the CLI directly
(you'll have to make sure you keep it up-to-date by running this periodically):

```sh
cargo install dsync
cargo install dsync
```

**CLI Usage**

* `-i`: input argument: path to schema file
* `-o`: output argument: path to directory where generated code should be written
* `-c`: connection type (for example: `diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::PgConnection>>`)
* `-g`: (optional) list of columns that are automatically generated by create/update triggers (for example, `created_at`, `updated_at`)
* `--tsync`: (optional) adds `#[tsync]` attribute to generated structs (see <https://github.com/Wulf/tsync>)
* `--model-path`: (optional) set a custom model import path, default `crate::models::`
* `--schema-path`: (optional) set a custom schema import path, default `crate::schema::`
* `--no-serde`: (optional) if set, does not output any serde related code
* `--no-crud`: (optional) Do not generate the CRUD functions for generated models
* `--create-str`: (optional) Set which string type to use for `Create*` structs (possible are `string`, `str`, `cow`)
* `--update-str`: (optional) Set which string type to use for `Update*` structs (possible are `string`, `str`, `cow`)
* `--single-model-file`: (optional) Generate only a single model file, instead of a directory with `mod.rs` and `generated.rs`
* note: the CLI has fail-safes to prevent accidental file overwriting
- `-i`: input argument: path to schema file
- `-o`: output argument: path to directory where generated code should be written
- `-c`: connection type that implements `diesel::connection::Connection`. For example:
- `diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::PgConnection>>`,
- `diesel::pg::PgConnection`
- `diesel::sqlite::SqliteConnection`
- `diesel::mysql::MysqlConnection`
- or, your custom diesel connection type!
- `-g`: (optional) list of columns that are automatically generated by create/update triggers (for example, `created_at`, `updated_at`)
- `--tsync`: (optional) adds `#[tsync]` attribute to generated structs (see <https://github.com/Wulf/tsync>)
- `--model-path`: (optional) set a custom model import path, default `crate::models::`
- `--schema-path`: (optional) set a custom schema import path, default `crate::schema::`
- `--no-serde`: (optional) if set, does not output any serde related code
- `--no-crud`: (optional) Do not generate the CRUD functions for generated models
- `--create-str`: (optional) Set which string type to use for `Create*` structs (possible are `string`, `str`, `cow`)
- `--update-str`: (optional) Set which string type to use for `Update*` structs (possible are `string`, `str`, `cow`)
- `--single-model-file`: (optional) Generate only a single model file, instead of a directory with `mod.rs` and `generated.rs`
- `--diesel-backend`: (optional) Specifies the diesel backend type (something which implements `diesel::backend::Backend`). For example:
- `diesel::pg::Pg`,
- `diesel::sqlite::Sqlite`,
- `diesel::mysql::Mysql`,
- or your own type!
- note: the CLI has fail-safes to prevent accidental file overwriting

```sh
dsync -i src/schema.rs -o src/models
Expand All @@ -130,6 +179,16 @@ See `dsync --help` for more information.

Feel free to open tickets for support or feature requests.

## Migrating from v0 to v1

- For those that use plural table names: English-based pluralization is no longer handled. If you had a table named `todos`, dsync will not generate a struct named `Todo` anymore, but instead, `struct Todos` will be generated. It might be easier to rename your tables entirely to singular case.
- Replace all instances of `/* This file is generated and managed by dsync */` with `/* @generated and managed by dsync */` in your generated model files.
- If using `dsync` as a library, add `..Default::default()` at the end of your args for the `GenerationConfig` struct. It sets the following new params to their default values:
- `once_common_structs: true`,
- `once_connection_type: true`,
- `diesel_backend: "diesel::pg::Pg"`,
- #[tsync] attributes are no longer included by default. To enable them, change the default table config options or supply `--tsync` if using the CLI.

## Development/Testing

Use `./test/test_all.sh` to run tests.
Expand Down
13 changes: 13 additions & 0 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ pub struct MainOptions {
/// Generate the "ConnectionType" type only once in a "common.rs" file
#[arg(long = "once-connection-type")]
pub once_connection_type: bool,

/// Set which diesel backend to use (something which implements `diesel::backend::Backend`)
/// Deisel provides the following backends:
/// - `diesel::pg::Pg`
/// - `diesel::sqlite::Sqlite`
/// - `diesel::mysql::Mysql`
///
/// See `crate::GenerationConfig::diesel_backend` for more details.
///
/// Default is "diesel::pg::Pg"
#[arg(long = "diesel-backend", default_value = "diesel::pg::Pg")]
pub diesel_backend: String,
}

#[derive(Debug, ValueEnum, Clone, PartialEq, Default)]
Expand Down Expand Up @@ -203,6 +215,7 @@ fn actual_main() -> dsync::Result<()> {
model_path: args.model_path,
once_common_structs: args.once_common_structs,
once_connection_type: args.once_connection_type,
diesel_backend: args.diesel_backend,
},
)?;

Expand Down
Loading