toasty_core/schema/app/index.rs
1use super::{FieldId, ModelId};
2use crate::schema::db::{IndexOp, IndexScope};
3
4/// An index defined on a model's fields.
5///
6/// Indices speed up queries by letting the database locate rows without a full
7/// table scan. An index can cover one or more fields, may enforce uniqueness,
8/// and may serve as the primary key.
9///
10/// Fields are split into *partition* fields (used for distribution in NoSQL
11/// backends like DynamoDB) and *local* fields (sort keys or secondary columns).
12///
13/// # Examples
14///
15/// ```
16/// use toasty_core::schema::app::{Index, IndexId, IndexField, ModelId};
17/// use toasty_core::schema::db::{IndexOp, IndexScope};
18///
19/// let index = Index {
20/// id: IndexId { model: ModelId(0), index: 0 },
21/// name: None,
22/// fields: vec![IndexField {
23/// field: ModelId(0).field(0),
24/// op: IndexOp::Eq,
25/// scope: IndexScope::Local,
26/// }],
27/// unique: true,
28/// primary_key: true,
29/// };
30/// assert!(index.unique);
31/// assert!(index.primary_key);
32/// ```
33#[derive(Debug, Clone)]
34pub struct Index {
35 /// Uniquely identifies this index within the schema.
36 pub id: IndexId,
37
38 /// User-provided index name from `#[index(name = "...", ...)]` or
39 /// `#[key(name = "...", ...)]`. When `None`, the schema builder generates
40 /// a name automatically.
41 pub name: Option<String>,
42
43 /// Fields included in the index, in order.
44 pub fields: Vec<IndexField>,
45
46 /// When `true`, the index enforces uniqueness across indexed entries.
47 pub unique: bool,
48
49 /// When `true`, this index represents the model's primary key.
50 pub primary_key: bool,
51}
52
53/// Uniquely identifies an [`Index`] within a schema.
54///
55/// Composed of the owning model's [`ModelId`] and a positional index into that
56/// model's index list.
57///
58/// # Examples
59///
60/// ```
61/// use toasty_core::schema::app::{IndexId, ModelId};
62///
63/// let id = IndexId { model: ModelId(0), index: 0 };
64/// assert_eq!(id.model, ModelId(0));
65/// ```
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub struct IndexId {
68 /// The model this index belongs to.
69 pub model: ModelId,
70 /// Positional index within the model's index list.
71 pub index: usize,
72}
73
74/// A single field entry within an [`Index`].
75///
76/// Describes which field is indexed, the comparison operation used for lookups,
77/// and whether this field is a partition key or a local (sort) key.
78///
79/// # Examples
80///
81/// ```
82/// use toasty_core::schema::app::{IndexField, ModelId};
83/// use toasty_core::schema::db::{IndexOp, IndexScope};
84///
85/// let field = IndexField {
86/// field: ModelId(0).field(1),
87/// op: IndexOp::Eq,
88/// scope: IndexScope::Local,
89/// };
90/// ```
91#[derive(Debug, Copy, Clone)]
92pub struct IndexField {
93 /// The field being indexed.
94 pub field: FieldId,
95
96 /// The comparison operation used when querying this index field.
97 pub op: IndexOp,
98
99 /// Whether this field is a partition key or a local (sort) key.
100 pub scope: IndexScope,
101}
102
103impl Index {
104 /// Returns the partition-scoped fields of this index.
105 ///
106 /// Partition fields come before local fields and determine data
107 /// distribution in NoSQL backends.
108 pub fn partition_fields(&self) -> &[IndexField] {
109 let i = self.index_of_first_local_field();
110 &self.fields[0..i]
111 }
112
113 /// Returns the local (sort-key) fields of this index.
114 ///
115 /// Local fields follow partition fields and determine ordering within a
116 /// partition.
117 pub fn local_fields(&self) -> &[IndexField] {
118 let i = self.index_of_first_local_field();
119 &self.fields[i..]
120 }
121
122 fn index_of_first_local_field(&self) -> usize {
123 self.fields
124 .iter()
125 .position(|field| field.scope.is_local())
126 .unwrap_or(self.fields.len())
127 }
128}