toasty_core/schema/mapping.rs
1//! Mapping between app-level models and database-level tables.
2//!
3//! The types in this module define how each model field corresponds to one or
4//! more database columns. The mapping supports:
5//!
6//! - Primitive fields that map 1:1 to a column
7//! - Embedded structs that flatten into multiple columns
8//! - Embedded enums stored as a discriminant column plus per-variant data columns
9//! - Relation fields that have no direct column storage
10//!
11//! The root type is [`Mapping`], which holds a [`Model`] entry for each model.
12//! Each `Model` contains per-field [`Field`] mappings and the expression
13//! templates ([`Model::model_to_table`] and [`TableToModel`]) used during
14//! query lowering.
15//!
16//! # Examples
17//!
18//! ```ignore
19//! use toasty_core::schema::mapping::Mapping;
20//!
21//! // Access the mapping for a specific model
22//! let model_mapping = mapping.model(model_id);
23//! println!("backed by table {:?}", model_mapping.table);
24//! ```
25
26mod field;
27pub use field::{EnumVariant, Field, FieldEnum, FieldPrimitive, FieldRelation, FieldStruct};
28
29mod model;
30pub use model::{Model, TableToModel};
31
32use super::app::ModelId;
33use indexmap::IndexMap;
34
35/// Defines the correspondence between app-level models and database-level
36/// tables.
37///
38/// The mapping is constructed during schema building and remains immutable at
39/// runtime. It provides the translation layer that enables the query engine to
40/// convert model-oriented statements into table-oriented statements during the
41/// lowering phase.
42///
43/// # Examples
44///
45/// ```ignore
46/// use toasty_core::schema::mapping::Mapping;
47/// use indexmap::IndexMap;
48///
49/// let mapping = Mapping { models: IndexMap::new() };
50/// assert_eq!(mapping.models.len(), 0);
51/// ```
52#[derive(Debug, Clone)]
53pub struct Mapping {
54 /// Per-model mappings indexed by model identifier.
55 pub models: IndexMap<ModelId, Model>,
56}
57
58impl Mapping {
59 /// Returns the mapping for the specified model.
60 ///
61 /// # Panics
62 ///
63 /// Panics if the model ID does not exist in the mapping.
64 ///
65 /// # Examples
66 ///
67 /// ```ignore
68 /// let model_mapping = mapping.model(model_id);
69 /// println!("table: {:?}", model_mapping.table);
70 /// ```
71 pub fn model(&self, id: impl Into<ModelId>) -> &Model {
72 self.models.get(&id.into()).expect("invalid model ID")
73 }
74
75 /// Returns a mutable reference to the mapping for the specified model.
76 ///
77 /// # Panics
78 ///
79 /// Panics if the model ID does not exist in the mapping.
80 ///
81 /// # Examples
82 ///
83 /// ```ignore
84 /// let model_mapping = mapping.model_mut(model_id);
85 /// // modify fields, columns, etc.
86 /// ```
87 pub fn model_mut(&mut self, id: impl Into<ModelId>) -> &mut Model {
88 self.models.get_mut(&id.into()).expect("invalid model ID")
89 }
90}