Skip to content

feat!: Expose on_delete and on_update fields for ForeignKey field#576

Open
ElijahAhianyo wants to merge 6 commits into
masterfrom
elijah/fk-on-delete-on-update
Open

feat!: Expose on_delete and on_update fields for ForeignKey field#576
ElijahAhianyo wants to merge 6 commits into
masterfrom
elijah/fk-on-delete-on-update

Conversation

@ElijahAhianyo
Copy link
Copy Markdown
Contributor

@ElijahAhianyo ElijahAhianyo commented May 19, 2026

Related issue or discussion

Fixes #540

Description

The code example below:

#[model]
#[derive(Debug, Clone)]
pub struct Customer {
    #[model(primary_key)]
    id: Auto<i64>,
}

#[model]
#[derive(Debug, Clone)]
pub struct Product {
    #[model(primary_key)]
    id: Auto<i64>,
}

#[model]
#[derive(Debug, Clone)]
pub struct Order {
    #[model(primary_key)]
    id: Auto<i64>,
    #[model(foreign_key(on_delete = "cascade"))]
    customer: ForeignKey<Customer>,
    #[model(foreign_key(on_delete = "cascade", on_update = "set_none"))]
    product: Option<ForeignKey<Product>>,
}

Generates the migration file below:

#[derive(Debug, Copy, Clone)]
pub(super) struct Migration;
impl ::cot::db::migrations::Migration for Migration {
    const APP_NAME: &'static str = "playground";
    const MIGRATION_NAME: &'static str = "m_0002_auto_20260519_011613";
    const DEPENDENCIES: &'static [::cot::db::migrations::MigrationDependency] = &[
        ::cot::db::migrations::MigrationDependency::migration("playground", "m_0001_initial"),
    ];
    const OPERATIONS: &'static [::cot::db::migrations::Operation] = &[
        ::cot::db::migrations::Operation::create_model()
            .table_name(::cot::db::Identifier::new("playground__product"))
            .fields(
                &[
                    ::cot::db::migrations::Field::new(
                            ::cot::db::Identifier::new("id"),
                            <cot::db::Auto<i64> as ::cot::db::DatabaseField>::TYPE,
                        )
                        .set_null(
                            <cot::db::Auto<i64> as ::cot::db::DatabaseField>::NULLABLE,
                        )
                        .auto()
                        .primary_key(),
                ],
            )
            .build(),
        ::cot::db::migrations::Operation::create_model()
            .table_name(::cot::db::Identifier::new("playground__customer"))
            .fields(
                &[
                    ::cot::db::migrations::Field::new(
                            ::cot::db::Identifier::new("id"),
                            <cot::db::Auto<i64> as ::cot::db::DatabaseField>::TYPE,
                        )
                        .set_null(
                            <cot::db::Auto<i64> as ::cot::db::DatabaseField>::NULLABLE,
                        )
                        .auto()
                        .primary_key(),
                ],
            )
            .build(),
        ::cot::db::migrations::Operation::create_model()
            .table_name(::cot::db::Identifier::new("playground__order"))
            .fields(
                &[
                    ::cot::db::migrations::Field::new(
                            ::cot::db::Identifier::new("id"),
                            <cot::db::Auto<i64> as ::cot::db::DatabaseField>::TYPE,
                        )
                        .set_null(
                            <cot::db::Auto<i64> as ::cot::db::DatabaseField>::NULLABLE,
                        )
                        .auto()
                        .primary_key(),
                    ::cot::db::migrations::Field::new(
                            ::cot::db::Identifier::new("customer"),
                            <cot::db::ForeignKey<
                                crate::Customer,
                            > as ::cot::db::DatabaseField>::TYPE,
                        )
                        .set_null(
                            <cot::db::ForeignKey<
                                crate::Customer,
                            > as ::cot::db::DatabaseField>::NULLABLE,
                        )
                        .foreign_key(
                            <crate::Customer as ::cot::db::Model>::TABLE_NAME,
                            <crate::Customer as ::cot::db::Model>::PRIMARY_KEY_NAME,
                            ::cot::db::ForeignKeyOnDeletePolicy::Cascade,
                            ::cot::db::ForeignKeyOnUpdatePolicy::Cascade,
                        ),
                    ::cot::db::migrations::Field::new(
                            ::cot::db::Identifier::new("product"),
                            <Option<
                                cot::db::ForeignKey<crate::Product>,
                            > as ::cot::db::DatabaseField>::TYPE,
                        )
                        .set_null(
                            <Option<
                                cot::db::ForeignKey<crate::Product>,
                            > as ::cot::db::DatabaseField>::NULLABLE,
                        )
                        .foreign_key(
                            <crate::Product as ::cot::db::Model>::TABLE_NAME,
                            <crate::Product as ::cot::db::Model>::PRIMARY_KEY_NAME,
                            ::cot::db::ForeignKeyOnDeletePolicy::Cascade,
                            ::cot::db::ForeignKeyOnUpdatePolicy::SetNone,
                        ),
                ],
            )
            .build(),
    ];
}

#[derive(::core::fmt::Debug)]
#[::cot::db::model(model_type = "migration")]
struct _Customer {
    #[model(primary_key)]
    id: cot::db::Auto<i64>,
}
#[derive(::core::fmt::Debug)]
#[::cot::db::model(model_type = "migration")]
struct _Order {
    #[model(primary_key)]
    id: cot::db::Auto<i64>,
    #[model(foreign_key(on_delete = "cascade"))]
    customer: cot::db::ForeignKey<crate::Customer>,
    #[model(foreign_key(on_delete = "cascade", on_update = "set_none"))]
    product: Option<cot::db::ForeignKey<crate::Product>>,
}
#[derive(::core::fmt::Debug)]
#[::cot::db::model(model_type = "migration")]
struct _Product {
    #[model(primary_key)]
    id: cot::db::Auto<i64>,
}

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Refactor / cleanup
  • Performance improvement
  • Other (describe above)

@github-actions github-actions Bot added C-cli Crate: cot-cli (issues and Pull Requests related to Cot CLI) C-codegen Crate: cot-codegen labels May 19, 2026
@ElijahAhianyo ElijahAhianyo marked this pull request as ready for review May 19, 2026 01:07
@ElijahAhianyo ElijahAhianyo marked this pull request as draft May 19, 2026 01:08
@ElijahAhianyo ElijahAhianyo changed the title Expose on_delete and on_update fields for ForeignKey field feat!: Expose on_delete and on_update fields for ForeignKey field May 19, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

🐰 Bencher Report

Branchelijah/fk-on-delete-on-update
Testbedgithub-ubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
microseconds (µs)
(Result Δ%)
Upper Boundary
microseconds (µs)
(Limit %)
empty_router/empty_router📈 view plot
🚷 view threshold
5,722.60 µs
(-6.37%)Baseline: 6,111.63 µs
7,723.65 µs
(74.09%)
json_api/json_api📈 view plot
🚷 view threshold
996.86 µs
(-7.30%)Baseline: 1,075.40 µs
1,324.49 µs
(75.26%)
nested_routers/nested_routers📈 view plot
🚷 view threshold
934.14 µs
(-5.98%)Baseline: 993.60 µs
1,204.82 µs
(77.53%)
single_root_route/single_root_route📈 view plot
🚷 view threshold
900.52 µs
(-5.83%)Baseline: 956.27 µs
1,168.37 µs
(77.07%)
single_root_route_burst/single_root_route_burst📈 view plot
🚷 view threshold
17,079.00 µs
(-3.43%)Baseline: 17,685.14 µs
21,147.11 µs
(80.76%)
🐰 View full continuous benchmarking report in Bencher

@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

❌ Patch coverage is 97.74011% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cot-codegen/src/model.rs 96.99% 3 Missing and 1 partial ⚠️
Flag Coverage Δ
rust 90.36% <97.74%> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cot-cli/src/migration_generator.rs 89.61% <100.00%> (+0.52%) ⬆️
cot-macros/src/lib.rs 94.84% <ø> (ø)
cot/src/db.rs 86.83% <ø> (ø)
cot-codegen/src/model.rs 95.57% <96.99%> (+0.88%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions Bot added C-lib Crate: cot (main library crate) C-macros Crate: cot-macros labels May 22, 2026
@ElijahAhianyo ElijahAhianyo marked this pull request as ready for review May 22, 2026 23:20
@ElijahAhianyo ElijahAhianyo requested a review from a team May 22, 2026 23:23
Copy link
Copy Markdown
Member

@seqre seqre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-cli Crate: cot-cli (issues and Pull Requests related to Cot CLI) C-codegen Crate: cot-codegen C-lib Crate: cot (main library crate) C-macros Crate: cot-macros

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose on_delete and on_update for ForeignKey fields

2 participants