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}