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/// fields: vec![IndexField {
22/// field: ModelId(0).field(0),
23/// op: IndexOp::Eq,
24/// scope: IndexScope::Local,
25/// }],
26/// unique: true,
27/// primary_key: true,
28/// };
29/// assert!(index.unique);
30/// assert!(index.primary_key);
31/// ```
32#[derive(Debug, Clone)]
33pub struct Index {
34 /// Uniquely identifies this index within the schema.
35 pub id: IndexId,
36
37 /// Fields included in the index, in order.
38 pub fields: Vec<IndexField>,
39
40 /// When `true`, the index enforces uniqueness across indexed entries.
41 pub unique: bool,
42
43 /// When `true`, this index represents the model's primary key.
44 pub primary_key: bool,
45}
46
47/// Uniquely identifies an [`Index`] within a schema.
48///
49/// Composed of the owning model's [`ModelId`] and a positional index into that
50/// model's index list.
51///
52/// # Examples
53///
54/// ```
55/// use toasty_core::schema::app::{IndexId, ModelId};
56///
57/// let id = IndexId { model: ModelId(0), index: 0 };
58/// assert_eq!(id.model, ModelId(0));
59/// ```
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub struct IndexId {
62 /// The model this index belongs to.
63 pub model: ModelId,
64 /// Positional index within the model's index list.
65 pub index: usize,
66}
67
68/// A single field entry within an [`Index`].
69///
70/// Describes which field is indexed, the comparison operation used for lookups,
71/// and whether this field is a partition key or a local (sort) key.
72///
73/// # Examples
74///
75/// ```
76/// use toasty_core::schema::app::{IndexField, ModelId};
77/// use toasty_core::schema::db::{IndexOp, IndexScope};
78///
79/// let field = IndexField {
80/// field: ModelId(0).field(1),
81/// op: IndexOp::Eq,
82/// scope: IndexScope::Local,
83/// };
84/// ```
85#[derive(Debug, Copy, Clone)]
86pub struct IndexField {
87 /// The field being indexed.
88 pub field: FieldId,
89
90 /// The comparison operation used when querying this index field.
91 pub op: IndexOp,
92
93 /// Whether this field is a partition key or a local (sort) key.
94 pub scope: IndexScope,
95}
96
97impl Index {
98 /// Returns the partition-scoped fields of this index.
99 ///
100 /// Partition fields come before local fields and determine data
101 /// distribution in NoSQL backends.
102 pub fn partition_fields(&self) -> &[IndexField] {
103 let i = self.index_of_first_local_field();
104 &self.fields[0..i]
105 }
106
107 /// Returns the local (sort-key) fields of this index.
108 ///
109 /// Local fields follow partition fields and determine ordering within a
110 /// partition.
111 pub fn local_fields(&self) -> &[IndexField] {
112 let i = self.index_of_first_local_field();
113 &self.fields[i..]
114 }
115
116 fn index_of_first_local_field(&self) -> usize {
117 self.fields
118 .iter()
119 .position(|field| field.scope.is_local())
120 .unwrap_or(self.fields.len())
121 }
122}