Skip to content
Merged
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
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ jobs:
cargo check --workspace --features sqlite,postgres,mysql,testing --exclude ui-tests
cargo check --workspace --features sqlite,testing --package ui-tests

packaging:
name: Packaging
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1

- name: Verify crates can be packaged
run: cargo package --workspace --all-features --exclude ui-tests

codestyle-markdown:
name: Codestyle (Markdown)
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
/target
target/
.env
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ All code examples should be executable via `mdbook test`. Use the

```rust
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let user = User::factory().create(&pool).await?;
assert_eq!(user.name, "Test User");
# Ok(())
Expand Down
12 changes: 6 additions & 6 deletions docs/src/concepts/factories.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ any fields you care about, then call `create()` to persist:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let product = Product::factory()
.name("Anvil 3000".to_string()) // Override name
.create(&pool) // id and price_cents: defaults
Expand Down Expand Up @@ -111,7 +111,7 @@ creates the parent record if none is specified:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// A User is auto-created — no manual setup needed
let order = Order::factory()
.create(&pool)
Expand Down Expand Up @@ -157,7 +157,7 @@ existing one:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// Pass a factory: creates a new user with specific attributes
let order = Order::factory()
.for_user(User::factory().name("Wile E.".to_string()))
Expand Down Expand Up @@ -202,7 +202,7 @@ an instance shares the **same** parent:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// A conversation between two specific people
let wile = User::factory()
.name("Wile E.".to_string())
Expand Down Expand Up @@ -251,7 +251,7 @@ children for a parent:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let user = User::factory()
.has_orders(Order::factory(), 3)
.create(&pool)
Expand Down Expand Up @@ -309,7 +309,7 @@ Missing parents are auto-created at every level of the chain:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// 1 order, 3 order lines, each with its own product
let order = Order::factory()
.has_order_lines(OrderLine::factory(), 3)
Expand Down
2 changes: 1 addition & 1 deletion docs/src/concepts/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ query builder for common operations. For instance:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// Insert a new record
let anvil = Product {
id: Uuid::new_v4(),
Expand Down
30 changes: 15 additions & 15 deletions docs/src/concepts/query-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ clauses, then execute the query by passing a connection:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory().price_cents(3000).in_stock(true).create(&pool).await?;
let deals: Vec<Product> = Product::query()
.r#where(Product::IN_STOCK, "=", true)
Expand Down Expand Up @@ -83,7 +83,7 @@ Fabrique provides dedicated methods:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# User::factory().deleted_at(None).create(&pool).await?;
let active = User::query()
.where_null(User::DELETED_AT)
Expand Down Expand Up @@ -123,7 +123,7 @@ how many records are returned and where to start:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory().in_stock(true).create(&pool).await?;
let page = Product::query()
.r#where(Product::IN_STOCK, "=", true)
Expand Down Expand Up @@ -159,7 +159,7 @@ a `Result`:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory().price_cents(3000).create(&pool).await?;
let cheapest: Option<Product> = Product::query()
.r#where(Product::PRICE_CENTS, "<=", 5000)
Expand Down Expand Up @@ -199,7 +199,7 @@ data:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
Product::insert()
.set(Product::ID, Uuid::new_v4())
.set(Product::NAME, "Anvil 3000")
Expand Down Expand Up @@ -231,7 +231,7 @@ the executor — this avoids a separate SELECT roundtrip:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let anvil: Product = Product::insert()
.set(Product::ID, Uuid::new_v4())
.set(Product::NAME, "Anvil 3000")
Expand Down Expand Up @@ -265,7 +265,7 @@ let anvil: Product = Product::insert()
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory().price_cents(30).create(&pool).await?;
Product::update()
.set(Product::PRICE_CENTS, 100)
Expand Down Expand Up @@ -314,7 +314,7 @@ no relationship is declared between the models, it won't compile:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Order::factory().create(&pool).await?;
// Both directions work — the relation is declared once
let users = User::query()
Expand Down Expand Up @@ -376,7 +376,7 @@ chain must be valid at each step:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Order::factory().create(&pool).await?;
// Order → OrderLine (direct) → Product (through OrderLine)
let orders = Order::query()
Expand Down Expand Up @@ -420,7 +420,7 @@ Each alias is a marker type generated by the `alias` attribute
# }
# #[fabrique::doctest]
# async fn main(
# pool: Pool<Backend>,
# pool: Pool<Sqlite>,
# ) -> Result<(), fabrique::Error> {
let messages = Message::query()
.join_as::<User, Sender>()
Expand Down Expand Up @@ -478,7 +478,7 @@ to build:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory().create(&pool).await?;
let products: Vec<Product> = Product::query()
.select_as::<Product, _>()
Expand Down Expand Up @@ -508,7 +508,7 @@ do:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory().create(&pool).await?;
// Equivalent — Product is inferred
let products: Vec<Product> = Product::query()
Expand Down Expand Up @@ -544,7 +544,7 @@ model:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Order::factory().create(&pool).await?;
let orders: Vec<Order> = User::query()
.join::<Order>()
Expand Down Expand Up @@ -575,7 +575,7 @@ constants — the return type matches:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory().create(&pool).await?;
let rows: Vec<(String, i32)> = Product::query()
.select((Product::NAME, Product::PRICE_CENTS))
Expand Down Expand Up @@ -611,7 +611,7 @@ present:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Order::factory().create(&pool).await?;
let rows: Vec<(String, String)> = User::query()
.join::<Order>()
Expand Down
6 changes: 3 additions & 3 deletions docs/src/concepts/relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ primary key — no declaration needed on the parent side:
# status: String,
# }
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# let user = User::factory().create(&pool).await?;
let orders = user.orders::<_>().get(&pool).await?;
# Ok(())
Expand Down Expand Up @@ -136,7 +136,7 @@ specify which foreign key to use:
# recipient_id: Uuid,
# }
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# let user = User::factory().create(&pool).await?;
let sent = user.messages::<_, Sender>().get(&pool).await?;
let received = user.messages::<_, Recipient>().get(&pool).await?;
Expand Down Expand Up @@ -168,7 +168,7 @@ through a specific alias:
# }
# #[fabrique::doctest]
# async fn main(
# pool: Pool<Backend>,
# pool: Pool<Sqlite>,
# ) -> Result<(), fabrique::Error> {
let messages = Message::query()
.join_as::<User, Sender>()
Expand Down
10 changes: 5 additions & 5 deletions docs/src/cookbook/bulk-update-and-upsert.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ touches every matching row:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory()
# .price_cents(15000)
# .in_stock(true)
Expand Down Expand Up @@ -68,7 +68,7 @@ Chain multiple `.set()` calls to update several columns at once:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory()
# .name("Anvil 3000".to_string())
# .price_cents(100)
Expand Down Expand Up @@ -113,7 +113,7 @@ separate SELECT:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# Product::factory()
# .price_cents(15000)
# .in_stock(true)
Expand Down Expand Up @@ -162,7 +162,7 @@ statement:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# let product = Product::factory()
# .name("Old Name".to_string())
# .create(&pool)
Expand Down Expand Up @@ -209,7 +209,7 @@ If you only want to skip duplicates without updating, use
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# let id = Uuid::new_v4();
// Insert if not exists, silently skip if exists
Product::insert()
Expand Down
10 changes: 5 additions & 5 deletions docs/src/cookbook/handle-ambiguous-relations.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ With aliases, you can join the same model multiple times using `join_as`:
# recipient_id: Uuid,
# }
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let messages = Message::query()
.join_as::<User, Sender>()
.join_as::<User, Recipient>()
Expand Down Expand Up @@ -111,7 +111,7 @@ Use `where_on` to filter on a specific alias:
# recipient_id: Uuid,
# }
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// Find messages sent by Alice
let messages = Message::query()
.join_as::<User, Sender>()
Expand Down Expand Up @@ -145,7 +145,7 @@ Use `order_by_on` to sort by a column from a specific alias:
# recipient_id: Uuid,
# }
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// Order messages by sender name
let messages = Message::query()
.join_as::<User, Sender>()
Expand Down Expand Up @@ -179,7 +179,7 @@ Aliases generate `for_<alias>` methods on the factory:
# recipient_id: Uuid,
# }
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let alice = User::factory()
.name("Alice".to_string())
.create(&pool)
Expand Down Expand Up @@ -228,7 +228,7 @@ to specify which foreign key to follow:
# email: String,
# }
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
# let user = User::factory().create(&pool).await?;
// Get messages sent by this user
let sent = user.messages::<_, Sender>().get(&pool).await?;
Expand Down
8 changes: 4 additions & 4 deletions docs/src/cookbook/simplify-test-setup-with-factories.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ them. With factories, the entire graph is built in one chain
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let order = Order::factory()
.has_order_lines(OrderLine::factory(), 3)
.create(&pool)
Expand Down Expand Up @@ -99,7 +99,7 @@ next ones reuse the same record:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let user = User::factory()
.name("Wile E. Coyote".to_string())
.create(&pool)
Expand Down Expand Up @@ -153,7 +153,7 @@ generate everything else:
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
// Arrange — only the status matters for this test
Order::factory()
.status("shipped".to_string())
Expand Down Expand Up @@ -216,7 +216,7 @@ Here, Alice and Bob each send 100 messages to each other —
# }
#
# #[fabrique::doctest]
# async fn main(pool: Pool<Backend>) -> Result<(), fabrique::Error> {
# async fn main(pool: Pool<Sqlite>) -> Result<(), fabrique::Error> {
let alice = User::factory()
.name("Alice".to_string())
.create(&pool)
Expand Down
Loading