Skip to main content

drizzle_core/traits/
index.rs

1use core::any::Any;
2
3use crate::{SQLParam, SQLSchemaType, SQLTable, TableRef, ToSQL};
4
5/// An index's metadata as associated constants, generated by the index
6/// macros.
7///
8/// Every `DrizzleIndex` also implements [`SQLIndexInfo`].
9pub trait DrizzleIndex: Send + Sync + 'static {
10    /// Index name.
11    const INDEX_NAME: &'static str;
12
13    /// Column names included in this index, in definition order.
14    const COLUMN_NAMES: &'static [&'static str];
15
16    /// Whether this is a unique index.
17    const IS_UNIQUE: bool = false;
18
19    /// The `WHERE` predicate of a partial index, as SQL text.
20    const WHERE_CLAUSE: Option<&'static str> = None;
21
22    /// The table this index belongs to.
23    fn table_ref() -> &'static TableRef;
24}
25
26// Every `DrizzleIndex` is a `SQLIndexInfo`.
27impl<T: DrizzleIndex> SQLIndexInfo for T {
28    fn table(&self) -> &'static TableRef {
29        T::table_ref()
30    }
31
32    fn name(&self) -> &'static str {
33        T::INDEX_NAME
34    }
35
36    fn columns(&self) -> &'static [&'static str] {
37        T::COLUMN_NAMES
38    }
39
40    fn is_unique(&self) -> bool {
41        T::IS_UNIQUE
42    }
43
44    fn where_clause(&self) -> Option<&'static str> {
45        T::WHERE_CLAUSE
46    }
47}
48
49/// Runtime metadata of an index, usable as a trait object.
50pub trait SQLIndexInfo: Any + Send + Sync {
51    /// The indexed table.
52    fn table(&self) -> &'static TableRef;
53    /// The index name.
54    fn name(&self) -> &'static str;
55
56    /// Column names included in this index, in definition order.
57    fn columns(&self) -> &'static [&'static str];
58
59    /// Whether this is a unique index.
60    fn is_unique(&self) -> bool {
61        false
62    }
63
64    /// The `WHERE` predicate of a partial index, as SQL text.
65    fn where_clause(&self) -> Option<&'static str> {
66        None
67    }
68}
69
70impl core::fmt::Debug for dyn SQLIndexInfo {
71    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
72        f.debug_struct("SQLIndexInfo")
73            .field("name", &self.name())
74            .field("is_unique", &self.is_unique())
75            .field("where_clause", &self.where_clause())
76            .field("columns", &self.columns())
77            .field("table", &self.table().name)
78            .finish()
79    }
80}
81
82/// An index for the dialect whose value type is `Value`. Renders as its
83/// `CREATE INDEX` statement.
84///
85/// Generated by `#[SQLiteIndex]`, `#[PostgresIndex]` and `#[MySQLIndex]` on a
86/// tuple struct listing the columns, such as
87/// `struct UserEmailIdx(Users::email);`.
88#[diagnostic::on_unimplemented(
89    message = "`{Self}` is not a SQL index for this dialect",
90    label = "ensure this type was derived with #[SQLiteIndex], #[PostgresIndex], or #[MySQLIndex]"
91)]
92pub trait SQLIndex<'a, Type: SQLSchemaType, Value: SQLParam + 'a>:
93    SQLIndexInfo + ToSQL<'a, Value>
94{
95    /// The indexed table.
96    type Table: SQLTable<'a, Type, Value>;
97}