Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SeaORM 0.12.x Docs - 1 #99

Merged
merged 27 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4b2d1c7
Optional Field SeaQL/sea-orm#1513
darkmmon Jul 11, 2023
ee0b0db
.gitignore SeaQL/sea-orm#1334
darkmmon Jul 11, 2023
e11d115
migration table custom name SeaQL/sea-orm#1511
darkmmon Jul 11, 2023
10618e0
OR condition relation SeaQL/sea-orm#1433
darkmmon Jul 11, 2023
c9ccb3e
DerivePartialModel SeaQL/sea-orm#1597
darkmmon Jul 11, 2023
f2316b5
space for migration file naming SeaQL/sea-orm#1570
darkmmon Jul 11, 2023
bae2602
composite key up to 12 SeaQL/sea-orm#1508
darkmmon Jul 11, 2023
7ea184d
seaography integration SeaQL/sea-orm#1599
darkmmon Jul 12, 2023
74e68f4
QuerySelect SimpleExpr SeaQL/sea-orm#1702
darkmmon Jul 12, 2023
8c9f82f
sqlErr SeaQL/sea-orm#1707
darkmmon Jul 12, 2023
d3b8d74
migration check SeaQL/sea-orm#1519
darkmmon Jul 12, 2023
bda6690
postgres array SeaQL/sea-orm#1565
darkmmon Jul 12, 2023
361d03d
param intoString SeaQL/sea-orm#1439
darkmmon Jul 12, 2023
315a9db
**skipped** re-export SeaQL/sea-orm#1661
darkmmon Jul 12, 2023
899dc96
ping SeaQL/sea-orm#1627
darkmmon Jul 12, 2023
4927f25
on empty do nothing SeaQL/sea-orm#1708
darkmmon Jul 12, 2023
4175aa9
on conflict do nothing SeaQL/sea-orm#1712
darkmmon Jul 12, 2023
1da2436
**skipped** upgrade versions
darkmmon Jul 12, 2023
5791b83
active enum fail safe SeaQL/sea-orm#1374
darkmmon Jul 12, 2023
980b896
relation generation check SeaQL/sea-orm#1435
darkmmon Jul 12, 2023
fd22e2b
entity generation bug SeaQL/sea-schema#105
darkmmon Jul 12, 2023
2cafa12
**skipped** bug fix that does not require edits
darkmmon Jul 12, 2023
c935396
EnumIter change SeaQL/sea-orm#1535
darkmmon Jul 12, 2023
8237cac
completed and fixed a previous todo SeaQL/sea-orm#1570
darkmmon Jul 12, 2023
c397d5b
amended wordings and structures
darkmmon Jul 13, 2023
f73c28b
Edit
billy1624 Jul 13, 2023
64dddad
Remove temp file
billy1624 Jul 13, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ Basically, they are in the form of `runtime-ASYNC_RUNTIME-TLS_LIB`:
+ `with-rust_decimal` - support [`rust_decimal`](https://crates.io/crates/rust_decimal) types
+ `with-bigdecimal` - support [`bigdecimal`](https://crates.io/crates/bigdecimal) types
+ `with-uuid` - support [`uuid`](https://crates.io/crates/uuid) types
+ `postgres-array` - support array types in Postgres
+ `postgres-array` - support array types in Postgres (automatically enabled when `sqlx-postgres` feature is turned on)
+ `sea-orm-internal` - opt-in unstable internal APIs (for accessing re-export SQLx types)
16 changes: 14 additions & 2 deletions SeaORM/docs/02-install-and-config/02-connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Multiple queries will execute in parallel as you `await` on them.
To configure the connection, use the [`ConnectOptions`](https://docs.rs/sea-orm/*/sea_orm/struct.ConnectOptions.html) interface:

```rust
let mut opt = ConnectOptions::new("protocol://username:password@host/database".to_owned());
let mut opt = ConnectOptions::new("protocol://username:password@host/database");
opt.max_connections(100)
.min_connections(5)
.connect_timeout(Duration::from_secs(8))
Expand All @@ -30,11 +30,23 @@ opt.max_connections(100)
.max_lifetime(Duration::from_secs(8))
.sqlx_logging(true)
.sqlx_logging_level(log::LevelFilter::Info)
.set_schema_search_path("my_schema".into()); // Setting default PostgreSQL schema
.set_schema_search_path("my_schema"); // Setting default PostgreSQL schema

let db = Database::connect(opt).await?;
```

## Checking Connection is Valid

Checks if a connection to the database is still valid.

```rust
|db: DatabaseConnection| {
assert!(db.ping().await.is_ok());
db.clone().close().await;
assert!(matches!(db.ping().await, Err(DbErr::ConnectionAcquire)));
}
```

## Closing Connection

The connection will be automatically closed on drop. To close the connection explicitly, call the `close` method.
Expand Down
23 changes: 22 additions & 1 deletion SeaORM/docs/03-migration/01-setting-up-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,26 @@ If you are starting from a fresh database, it's better to version control your d

## Migration Table

A table named `seaql_migrations` will be created in your database to keep track of the applied migrations. It will be created automatically when you run the migration.
A table will be created in your database to keep track of the applied migrations. It will be created automatically when you run the migration.

By default, it will be named `seaql_migrations`. You can also use a custom name for your migration table.

```rust
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20220118_000001_create_cake_table::Migration),
Box::new(m20220118_000002_create_fruit_table::Migration),
]
}

// Override the name of migration table
fn migration_table_name() -> sea_orm::DynIden {
Alias::new("override_migration_table_name").into_iden()
}
}
```

## Creating Migration Directory

Expand Down Expand Up @@ -45,6 +64,8 @@ migration
└── main.rs # Migrator CLI, for running manually
```

Note that if you setup the migration directory directly within a Git repository, a `.gitignore` file will also be created.

## Workspace Structure

It is recommended to structure your cargo workspace as follows to share SeaORM entities between the app crate and the migration crate. Checkout the [integration examples](https://github.com/SeaQL/sea-orm/tree/master/examples) for demonstration.
Expand Down
5 changes: 5 additions & 0 deletions SeaORM/docs/03-migration/02-writing-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ Each migration contains two methods: `up` and `down`. The `up` method is used to

Generate a new migration file by executing `sea-orm-cli migrate generate` command.

If you name the file with spaces, it will be converted according to the convention automatically.

```shell
sea-orm-cli migrate generate NAME_OF_MIGRATION [--local-time]

# E.g. to generate `migration/src/m20220101_000001_create_table.rs` shown below
sea-orm-cli migrate generate create_table

# This create the same migration file as above command
sea-orm-cli migrate generate "create table"
```

Or you can create a migration file using the template below. Name the file according to the naming convention `mYYYYMMDD_HHMMSS_migration_name.rs`.
Expand Down
17 changes: 15 additions & 2 deletions SeaORM/docs/03-migration/03-running-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,24 @@ For CLI, you can specify the target schema with `-s` / `--database_schema` optio
You can also run the migration on the target schema programmatically:

```rust
let connect_options = ConnectOptions::new("postgres://root:root@localhost/database".into())
.set_schema_search_path("my_schema".into()) // Override the default schema
let connect_options = ConnectOptions::new("postgres://root:root@localhost/database")
.set_schema_search_path("my_schema") // Override the default schema
.to_owned();

let db = Database::connect(connect_options).await?

migration::Migrator::up(&db, None).await?;
```

## Checking Migration Status

You can use `Migration::name()` and `Migration::status()` to get the name and status of a `sea_orm_migration::Migration`

```rust
let migrations = Migrator::get_pending_migrations(db).await?;
assert_eq!(migrations.len(), 5);

let migration = migrations.get(0).unwrap();
assert_eq!(migration.name(), "m20220118_000002_create_fruit_table");
assert_eq!(migration.status(), MigrationStatus::Pending);
```
1 change: 1 addition & 0 deletions SeaORM/docs/04-generate-entity/01-sea-orm-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Command line options:
- `--max-connections`: maximum number of database connections to be initialized in the connection pool (default: `1`)
- `--model-extra-derives`: append extra derive macros to the generated model struct
- `--model-extra-attributes`: append extra attributes to generated model struct
- `--seaography`: an additional RelatedEntity enum for seaography integration will be generated.

```shell
# Generate entity files of database `bakery` to `entity/src`
Expand Down
2 changes: 2 additions & 0 deletions SeaORM/docs/04-generate-entity/02-entity-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ pub id: i32

This is usually the case in junction tables, where a two-column tuple is used as the primary key. Simply annotate multiple columns to define a composite primary key. By default, `auto_increment` is `false` for composite key.

You can define up to 12 primary key in a model.

```rust
pub struct Model {
#[sea_orm(primary_key)]
Expand Down
26 changes: 26 additions & 0 deletions SeaORM/docs/05-basic-crud/03-insert.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,18 @@ let res: InsertResult = Fruit::insert_many([apple, orange]).exec(db).await?;
assert_eq!(res.last_insert_id, 30)
```

Supplying an empty iterator to `insert_many` method will yield an error. However, you can change the behaviour with `on_empty_do_nothing` method to handle inserting an empty iterator properly.

```rust
// now, you can do:
let res = Bakery::insert_many(std::iter::empty())
.on_empty_do_nothing()
.exec(db)
.await;

assert!(matches!(res, Ok(TryInsertResult::Empty)));
```

## On Conflict

Insert active model with on conflict behaviour.
Expand Down Expand Up @@ -269,3 +281,17 @@ let res = Entity::insert_many([

assert_eq!(res.err(), Some(DbErr::RecordNotInserted));
```

Or you can use `.do_nothing()` to handle insert with conflict properly.

```rust
let on = OnConflict::column(Column::Id).do_nothing().to_owned();

// Existing behaviour
let res = Entity::insert_many([..]).on_conflict(on).exec(db).await;
assert!(matches!(res, Err(DbErr::RecordNotInserted)));

// you can also:
let res = Entity::insert_many([..]).on_conflict(on).do_nothing().exec(db).await;
assert!(matches!(res, Ok(TryInsertResult::Conflicted)));
```
6 changes: 3 additions & 3 deletions SeaORM/docs/05-basic-crud/08-raw-sql.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ You can build SQL statements using `sea-query` and query / execute it directly o
let query_res: Option<QueryResult> = db
.query_one(Statement::from_string(
DatabaseBackend::MySql,
"SELECT * FROM `cake`;".to_owned(),
"SELECT * FROM `cake`;",
))
.await?;
let query_res = query_res.unwrap();
Expand All @@ -97,7 +97,7 @@ let id: i32 = query_res.try_get("", "id")?;
let query_res_vec: Vec<QueryResult> = db
.query_all(Statement::from_string(
DatabaseBackend::MySql,
"SELECT * FROM `cake`;".to_owned(),
"SELECT * FROM `cake`;",
))
.await?;
```
Expand All @@ -108,7 +108,7 @@ let query_res_vec: Vec<QueryResult> = db
let exec_res: ExecResult = db
.execute(Statement::from_string(
DatabaseBackend::MySql,
"DROP DATABASE IF EXISTS `sea`;".to_owned(),
"DROP DATABASE IF EXISTS `sea`;",
))
.await?;
assert_eq!(exec_res.rows_affected(), 1);
Expand Down
41 changes: 41 additions & 0 deletions SeaORM/docs/06-relation/03-many-to-many.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,44 @@ pub enum Relation {
Filling,
}
```

Note that the implementation of `Related<R>` with `via` and `to` methods will not be generated if there exists multiple paths via an intermediate table.

For example, in the schema defined below, there are two paths:
- Path 1. `users <-> users_votes <-> bills`
- Path 2. `users <-> users_saved_bills <-> bills`

Therefore, the implementation of `Related<R>` will not be generated

```sql
CREATE TABLE users
(
id uuid PRIMARY KEY DEFAULT uuid_generate_v1mc(),
email TEXT UNIQUE NOT NULL,
...
);
```
```sql
CREATE TABLE bills
(
id uuid PRIMARY KEY DEFAULT uuid_generate_v1mc(),
...
);
```
```sql
CREATE TABLE users_votes
(
user_id uuid REFERENCES users (id) ON UPDATE CASCADE ON DELETE CASCADE,
bill_id uuid REFERENCES bills (id) ON UPDATE CASCADE ON DELETE CASCADE,
vote boolean NOT NULL,
CONSTRAINT users_bills_pkey PRIMARY KEY (user_id, bill_id)
);
```
```sql
CREATE TABLE users_saved_bills
(
user_id uuid REFERENCES users (id) ON UPDATE CASCADE ON DELETE CASCADE,
bill_id uuid REFERENCES bills (id) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT users_saved_bills_pkey PRIMARY KEY (user_id, bill_id)
);
```
25 changes: 24 additions & 1 deletion SeaORM/docs/06-relation/06-custom-join-condition.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ It can be done via one of the following ways.

Add your additional join conditions directly to the relation enum. The easiest way is to provide a `sea_query::SimpleExpr` via `on_condition` procedural macros attribute.

If you want to have a `OR` condition relation, you can use `condition_type = "any"` to alter the relation.

```rust
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
Expand All @@ -29,6 +31,13 @@ pub enum Relation {
on_condition = r#"super::fruit::Column::Name.like("%tropical%")"#
)]
TropicalFruit,
// specify `condition_type = "any"` to override it
#[sea_orm(
has_many = "super::fruit::Entity",
on_condition = r#"super::fruit::Column::Name.like("%tropical%")"#
condition_type = "any",
)]
OrTropicalFruit,
}
```

Expand Down Expand Up @@ -126,7 +135,7 @@ assert_eq!(

## Custom Join

Last but not least, custom join conditions can be defined at the point you construct the join expression.
Last but not least, custom join conditions can be defined at the point you construct the join expression. Overriding condition relation can also be done in custom join on the fly.

```rust
assert_eq!(
Expand All @@ -153,6 +162,19 @@ assert_eq!(
.into_condition()
})
)
.join_as_rev(
JoinType::LeftJoin,
cake_filling::Relation::Cake
.def()
// chained AND / OR join on condition
.condition_type(ConditionType::Any)
.on_condition(|left, _right| {
Expr::col((left, cake_filling::Column::CakeId))
.gt(10)
.into_condition()
}),
Alias::new("cake_filling_alias")
)
.join(JoinType::LeftJoin, filling::Relation::Vendor.def())
.build(DbBackend::MySql)
.to_string(),
Expand All @@ -161,6 +183,7 @@ assert_eq!(
"LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` AND `fruit`.`name` LIKE '%tropical%'",
"LEFT JOIN `cake_filling` ON `cake`.`id` = `cake_filling`.`cake_id` AND `cake_filling`.`cake_id` > 10",
"LEFT JOIN `filling` ON `cake_filling`.`filling_id` = `filling`.`id` AND `filling`.`name` LIKE '%lemon%'",
"LEFT JOIN `cake_filling` AS `cake_filling_alias` ON `cake_filling_alias`.`cake_id` = `cake`.`id` OR `cake_filling_alias`.`cake_id` > 10",
"LEFT JOIN `vendor` ON `filling`.`vendor_id` = `vendor`.`id`",
]
.join(" ")
Expand Down
66 changes: 66 additions & 0 deletions SeaORM/docs/08-advanced-query/01-custom-select.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,33 @@ assert_eq!(
);
```

### Optional field

Since 0.12, SeaORM supports for partial select of `Option<T>` model field. A `None` value will be filled when the select result does not contain the `Option<T>` field without throwing an error.

```rust
customer::ActiveModel {
name: Set("Alice".to_owned()),
notes: Set(Some("Want to communicate with Bob".to_owned())),
..Default::default()
}
.save(db)
.await?;

// The `notes` field was intentionally leaved out
let customer = Customer::find()
.select_only()
.column(customer::Column::Id)
.column(customer::Column::Name)
.one(db)
.await
.unwrap();

// The select result does not contain `notes` field.
// Since it's of type `Option<String>`, it'll be `None` and no error will be thrown.
assert_eq!(customers.notes, None);
```

## Select Custom Expressions

Select any custom expression with `column_as` method, it takes any [`sea_query::SimpleExpr`](https://docs.rs/sea-query/*/sea_query/expr/enum.SimpleExpr.html) and an alias. Use [`sea_query::Expr`](https://docs.rs/sea-query/*/sea_query/expr/struct.Expr.html) helper to build `SimpleExpr`.
Expand All @@ -74,6 +101,45 @@ assert_eq!(
);
```

Alternatively, you can simply select with `expr`, `exprs` and `expr_as` methods.

```rust
use sea_orm::sea_query::Expr;
use sea_orm::{entity::*, tests_cfg::cake, DbBackend, QuerySelect, QueryTrait};

assert_eq!(
cake::Entity::find()
.select_only()
.expr(Expr::col((cake::Entity, cake::Column::Id)))
.build(DbBackend::MySql)
.to_string(),
"SELECT `cake`.`id` FROM `cake`"
);

assert_eq!(
cake::Entity::find()
.select_only()
.exprs([
Expr::col((cake::Entity, cake::Column::Id)),
Expr::col((cake::Entity, cake::Column::Name)),
])
.build(DbBackend::MySql)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name` FROM `cake`"
);

assert_eq!(
cake::Entity::find()
.expr_as(
Func::upper(Expr::col((cake::Entity, cake::Column::Name))),
"name_upper"
)
.build(DbBackend::MySql)
.to_string(),
"SELECT `cake`.`id`, `cake`.`name`, UPPER(`cake`.`name`) AS `name_upper` FROM `cake`"
);
```

## Handling Select Results

### Custom Struct
Expand Down
Loading