1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! Model-inheritance patterns: how to share fields and behaviour
//! between models.
//!
//! Rust has no class inheritance, but each of the usual shapes —
//! an abstract base, a multi-table split, a proxy view over one
//! table — has a counterpart the framework already supports.
//!
//! ### 1. Abstract base classes → traits
//!
//! Put the shared methods in a trait and `impl` it on each model.
//! Rust cannot share field declarations, so repeat those per model.
//!
//! ```ignore
//! use chrono::{DateTime, Utc};
//!
//! /// Shared "timestamps" behavior. Implemented on every model that
//! /// wants the `created_at` / `updated_at` audit pair.
//! pub trait Timestamped {
//! fn created_at(&self) -> DateTime<Utc>;
//! fn updated_at(&self) -> DateTime<Utc>;
//! }
//!
//! #[derive(rustango::Model)]
//! pub struct Article {
//! #[rustango(primary_key)]
//! pub id: rustango::core::Auto<i64>,
//! #[rustango(max_length = 200)]
//! pub title: String,
//! pub created_at: DateTime<Utc>,
//! pub updated_at: DateTime<Utc>,
//! }
//!
//! impl Timestamped for Article {
//! fn created_at(&self) -> DateTime<Utc> { self.created_at }
//! fn updated_at(&self) -> DateTime<Utc> { self.updated_at }
//! }
//! ```
//!
//! Any helper that takes `<T: Timestamped>` then works for every
//! model that implements it.
//!
//! ### 2. Multi-table inheritance → an explicit one-to-one FK
//!
//! Use `#[rustango(o2o = "parent_table", on = "parent_id")]`:
//!
//! ```ignore
//! #[derive(rustango::Model)]
//! #[rustango(table = "place")]
//! pub struct Place {
//! #[rustango(primary_key)]
//! pub id: rustango::core::Auto<i64>,
//! #[rustango(max_length = 200)]
//! pub name: String,
//! #[rustango(max_length = 200)]
//! pub address: String,
//! }
//!
//! #[derive(rustango::Model)]
//! #[rustango(table = "restaurant")]
//! pub struct Restaurant {
//! /// One-to-one back to Place — semantically "Restaurant IS-A Place".
//! #[rustango(primary_key)]
//! #[rustango(o2o = "place", on = "id")]
//! pub place_id: i64,
//! pub serves_hot_dogs: bool,
//! }
//! ```
//!
//! To read parent and child fields together, use
//! `Restaurant::objects().select_related("place_id")`.
//!
//! ### 3. Proxy models → extension trait
//!
//! A proxy is one table with several sets of helper methods. In Rust
//! that is an extension trait on `QuerySet<T>`. See [`crate::manager`]
//! for the full pattern.
//!
//! ```ignore
//! pub trait PublishedArticleExt: Sized {
//! fn only_published(self) -> Self;
//! }
//! impl PublishedArticleExt for rustango::query::QuerySet<Article> {
//! fn only_published(self) -> Self {
//! use rustango::core::Column as _;
//! self.where_(Article::published.eq(true))
//! }
//! }
//!
//! // Acts as a "PublishedArticle" proxy:
//! Article::objects().only_published().fetch(&pool).await?;
//! ```
//!
//! ## Summary
//!
//! | What you want | Rust idiom |
//! |---------------|-----------|
//! | Abstract base class | trait, plus the fields on each model |
//! | Multi-table inheritance | explicit `#[rustango(o2o)]` FK |
//! | Proxy model | extension trait on `QuerySet<T>` |
//!
//! There is no `#[rustango(abstract)]` attribute. Copying parent
//! fields at macro time would need the `Model` derive to read another
//! struct, and traits are more flexible: a model can implement many
//! of them, but could only have one abstract parent.
// Doc-only module; the patterns live in `tests/inheritance_patterns.rs`.